runtime的用法
RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 )。编译完成之后直接顺序执行,无任何二义性。OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。
那OC是怎么实现动态调用的呢?下面我们来看看OC通过发送消息来达到动态调用的秘密。假如在OC中写了这样的一个代码:
1
|
[obj makeText];
|
其中obj是一个对象,makeText是一个函数名称。对于这样一个简单的调用。在编译时RunTime会将上述代码转化成
1
|
objc_msgSend(obj,@selector(makeText));
|
首先我们来看看obj这个对象,iOS中的obj都继承于NSObject。
1
2
3
|
@interface NSObject <nsobject> {
Class isa OBJC_ISA_AVAILABILITY;
}</nsobject>
|
在NSObjcet中存在一个Class的isa指针。然后我们看看Class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
typedef struct objc_class *Class;
struct objc_class {
Class isa; // 指向metaclass
Class super_class ; // 指向其父类
const char *name ; // 类名
long version ; // 类的版本信息,初始化默认为0,可以通过runtime函数class_setVersion和class_getVersion进行修改、读取
long info; // 一些标识信息,如CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含对象方法和成员变量;CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法;
long instance_size ; // 该类的实例变量大小(包括从父类继承下来的实例变量);
struct objc_ivar_list *ivars; // 用于存储每个成员变量的地址
struct objc_method_list **methodLists ; // 与 info 的一些标志位有关,如CLS_CLASS (0x1L),则存储对象方法,如CLS_META (0x2L),则存储类方法;
struct objc_cache *cache; // 指向最近使用的方法的指针,用于提升效率;
struct objc_protocol_list *protocols; // 存储该类遵守的协议
}
|
我们可以看到,对于一个Class类中,存在很多东西,下面我来一一解释一下:
Class isa:指向metaclass,也就是静态的Class。一般一个Obj对象中的isa会指向普通的Class,这个Class中存储普通成员变量和对 象方法(“-”开头的方法),普通Class中的isa指针指向静态Class,静态Class中存储static类型成员变量和类方法(“+”开头的方 法)。
Class super_class:指向父类,如果这个类是根类,则为NULL。
注意:所有metaclass中isa指针都指向跟metaclass。而跟metaclass则指向自身。Root metaclass是通过继承Root class产生的。与root class结构体成员一致,也就是前面提到的结构。不同的是Root metaclass的isa指针指向自身。
Class类中其他的成员这里就先不做过多解释了,下面我们来看看:
@selector (makeText):这是一个SEL方法选择器。SEL其主要作用是快速的通过方法名字(makeText)查找到对应方法的函数指针,然后调用其函 数。SEL其本身是一个Int类型的一个地址,地址中存放着方法的名字。对于一个类中。每一个方法对应着一个SEL。所以iOS类中不能存在2个名称相同 的方法,即使参数类型不同,因为SEL是根据方法名字生成的,相同的方法名称只能对应一个SEL。
下面我们就来看看具体消息发送之后是怎么来动态查找对应的方法的。
首先,编译器将代码[obj makeText];转化为objc_msgSend(obj, @selector (makeText));,在objc_msgSend函数中。首先通过obj的isa指针找到obj对应的class。在Class中先去cache中 通过SEL查找对应函数method(猜测cache中method列表是以SEL为key通过hash表来存储的,这样能提高函数查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,则取superClass中查找。若能找到,则将method加 入到cache中,以方便下次查找,并通过method中的函数指针跳转到对应的函数中去执行。
下面总结我用到的一些runtime的例子.
1.找到类的属性
unsigned int count = 0;
Ivar *ivar = class_copyIvarList([Obj class], &count);
for (int i = 0; i<count; i++) {
Ivar var = ivar[i];
const char *varName = ivar_getName(var);
NSString *objname = [NSString stringWithUTF8String:varName];
if ([objname isEqualToString:@"_name"]) { //这里别忘了给属性加下划线
object_setIvar(obj, var, @"string");
break;
}
}
2.找类中的方法(包括私有方法)
unsigned int count=0;
Method * methodlist=class_copyMethodList([obj class], &count);
for (int i=0; i<count; i++) {
SEL methodname=method_getName(methodlist[i]);
NSString * methodstring=[NSString stringWithCString:sel_getName(methodname) encoding:NSUTF8StringEncoding];
NSLog(@"打印方法=%@",methodstring);
Method method1=class_getClassMethod([obj class], methodname);
}
3.添加方法
class_addMethod([obj class], @selector(guessperson), (IMP)guessAnswer, "v@:");
if ([self.person respondsToSelector:@selector(guessperson)]) {
//Method method = class_getInstanceMethod([obj1 class], @selector(guess));
[self.person performSelector:@selector(guessperson)];
} else{
NSLog(@"Sorry,I don't know");
}
void guessAnswer(id self,SEL _cmd){
NSLog(@"i am from beijing");
}
4.交换方法:
Method m1 = class_getInstanceMethod([obj class], @selector(sayName));//找到实例方法
Method m2 = class_getInstanceMethod([obj class], @selector(saySex));
Method m3 = class_getClassMethod([obj class], @selector(selfwrite));//获取类方法
Method m4 = class_getInstanceMethod([obj class], @selector(sayName));
method_exchangeImplementations(m1, m2);//交换两个方法,即方法m1执行m2的方法,m2执行m1的方法
转载于:https://www.cnblogs.com/fucw/p/6651057.html
runtime的用法相关推荐
- Runtime 的用法
Runtime 的用法 1.该类主要代表了应用程序的运行环境.一个RunTime就代表一个运行环境. 2.RunTime类常用的方法: (1) getRuntime():该方法用于返回当前应用程序的运 ...
- openxr runtime Monado 源码解析 源码分析:CreateSwapchain 画布 HardwareBuffer共享纹理 渲染线程 xrEndeFrame comp_renderer
monado系列文章索引汇总: openxr runtime Monado 源码解析 源码分析:源码编译 准备工作说明 hello_xr解读 openxr runtime Monado 源码解析 源码 ...
- html打开新窗口设置窗口属性,HTML之:让网页中的a标签属性统一设置-如‘新窗口打开’...
在开发过程中,我们往往想在页面中,给设置一个统一的默认格式,例如我们想让链接:"在新窗口打开",我们就可以使用标签 在网页中添加这段代码: [注解] 标签为页面上的所有链接规定默认 ...
- 如何在Java中将字节数组转换为十六进制字符串?
我有一个用十六进制数字填充并打印的字节数组,简单的方法是毫无意义的,因为有许多不可打印的元素. 我需要的是以下形式的确切十六进制代码: 3a5f771c #1楼 最简单的解决方案,没有外部库,没有数字 ...
- IOS-Swift面试相关基础
文章目录 Xcode部分 Storyboard基础控件: 控件: 基础交互手势: 计算机组成部分 内存管理 一.存储器 二.App启动运行过程 三.RAM内存分布 栈区(stack): 堆区(heap ...
- System 类 和 Runtime 类的常用用法
System类的常用用法 1,主要获取系统的环境变量信息 public static void sysProp()throws Exception{Map<String,String> e ...
- RunTime.getRunTime().addShutdownHook的用法
转载自 https://www.liangzl.com/get-article-detail-8064.html 有时候我们用到的程序不一定总是在JVM里面驻守,可能调用完就不用了,释放资源. Run ...
- 【转】RunTime.getRunTime().addShutdownHook用法
Runtime.getRuntime().addShutdownHook(shutdownHook); 这个方法的含义说明: 这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行 ...
- java 调用cmd_java打开本地应用程序(调用cmd)---Runtime用法详解
有时候我们需要借助java程序打开电脑自带的一些程序,可以直接打开或者借助cmd命令窗口打开一些常用的应用程序或者脚本,在cmd窗口执行的命令都可以通过这种方式运行. 例如: packagecn.xm ...
最新文章
- LeetCode Find the Difference
- 【NLP】ACL2020 | 词向量性别偏见
- Dubbo——Dubbo协议整合Jackson序列化解决方案
- 查看ie保存的表单_小学信息技术gt;搜索保存网页教师资格证面试模板
- SpringBoot:Could not autowire there is more than one bean of xx type
- 人工智能技术的三大学派_什么是人工智能?它离我们有多远
- 【mac】Bartender 2不能隐藏百度云同步盘图标的解决方法
- AngularJS2.0教程(一)快速上手之基础知识
- jQuery CSS 添加/删除类名
- Swift: Swift中Selector的变化
- 早上运动和晚上运动,哪个更利于减肥?
- 胜为蓝牙适配器驱动_udc 324b蓝牙驱动下载-胜为udc 324b蓝牙适配器驱动(win7/win10)v6.5.1.2700 官方版 - 极光下载站...
- 孙玄/陈东:聊一聊ZooKeeper的顺序一致性
- mac 终极教程,最全,最实用的教程
- IP地址后面/24/26/27/28/29/30网关数量分别是多少?如何计算?
- 阿里云科学家丁险峰:万物互联的价值在哪里?
- one 主格 复数 宾格_数字 主格宾格复数所有格
- GPU渲染管线与可编程着色器
- WINDOWS XP中使用DOS命令查看分区的格式
- 成像系统(一):A Review of Indocyanine Green Fluorescent Imaging in Surgery