runtime是什么
runtime是系统运行时的一些机制,C语言中,函数的调用在编译的时候就会决定调用哪个函数,然后再顺序执行。
OC不同,OC是动态语言,所谓的动态是指,可以在编译时更改。这时我们就要用到runtime。OC是面向对象的语言,在编译的时候会都会最终转化成C语言,也就是runtime代码。这个时候我们可以修改runtime代码来改变代码最终的执行效果。
runtime的运行机制
runtime主要通过消息转发运行。消息机制的头文件主要是这个<objc/message.h>
先来看runtime的消息传递机制void objc_msgSend(id self, SEL cmd, ...)
比如OC方法调用:id returnValue = [someObject messageName:parameter];
someObject叫做“接收者”(receiver),messageName是方法(selector)。方法与参数合起来称为“消息”(message)
在runtime时就会转化为:id returnValue = objc_msgSend(someObject,@selector(messageName:),parameter);
在我们点开<objc/runtime.h>
可以找到这样一个结构体。这个结构体就是表示一个类。
|
|
我们可以看到这个类中有struct objc_method_list **methodLists和struct objc_cache *cache
一个是这个类所属的方法列表,另一个是缓存列表。当我们向某个类发送消息的时候首先会先在该类的缓存列表查找是有该方法,这样效率会大大提高,当缓存列表里面没有该方法的时候就会到方法列表里面查找,如果方法列表里面也没有,那就会去父类查找,直到NSObject
,找到后就把这个方法放到缓存列表中,下次调用这个方法的时候就能直接在缓存列表中找到。objc_msgSend
方法是用得比较多的,头文件下其他方法用的不多,是一些特殊情况。这里就不赘述了。
如果上面最终没有找到对应的方法,则启动
[消息转发机制](http://book.51cto.com/art/201403/432146.html
runtime相关方法属性解析
我们继续在<objc/runtime.h>
文件往下看。id object_copy(id obj, size_t size)
这个方法拷贝一个对象,用于MRC,不适用ARC。id object_dispose(id obj)
释放一个对象所占用的内存object_getClassName(id obj)
返回类的名称void *object_getIndexedIvars(id obj)
当你创建一个 Objective-C对象时,runtime会在实例变量存储区域后面再分配一点额外的空间。这么做的目的是什么呢?你可以获取这块空间起始指针(用 object_getIndexedIvars
),然后就可以索引实例变量(ivars)
id object_getIvar(id obj, Ivar ivar)
获得类的变量与Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)
配合使用void object_setIvar(id obj, Ivar ivar, id value)
给一个对象的属性设置新值与Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)
配合使用
- 备注
class和metaclass的区别class 是 instance object 的类类型。当我们向实例对象发送消息(实例方法)时,我们在该实例对象的 class 结构的 methodlists 中去查找响应的函数,如果没找到匹配的响应函数则在该 class 的父类中的 methodlists 去查找(查找链为上图的中间那一排)。如下面的代码中,向str 实例对象发送 lowercaseString 消息,会在 NSString 类结构的 methodlists 中去查找 lowercaseString 的响应函数。NSString * str; [str lowercaseString];
metaclass 是 class object 的类类型。当我们向类对象发送消息(类方法)时,我们在该类对象的 metaclass 结构的 methodlists 中去查找响应的函数,如果没有找到匹配的响应函数则在该 metaclass 的父类中的 methodlists 去查找(查找链为上图的最右边那一排)。如下面的代码中,向 NSString 类对象发送 stringWithString 消息,会在 NSString 的 metaclass 类结构的 methodlists 中去查找 stringWithString 的响应函数。[NSString stringWithString:@"str"];
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
获取类的所有属性,那么和class_copyPropertyList
有什么区别呢?class_copyPropertyList
返回的仅仅是对象类的属性(@property申明的属性),而class_copyIvarList
返回类的所有属性和变量(包括在@interface大括号中声明的变量)class_getInstanceMethod
得到类的实例方法class_getClassMethod
得到类的类方法class_copyMethodList
获取类的方法列表,包括get和set方法class_conformsToProtocol
是只检查当前类符不符合协议class_addMethod
给类添加方法class_replaceMethod
动态替换方法class_addIvar
给类动态添加属性和class_addProperty
一样class_replaceProperty
属性替换class_createInstance
创建一个实例对象,method_getName
获取方法名称method_exchangeImplementations
动态交换2个方法objc_getAssociatedObject
关联对象objc_removeAssociatedObjects
移除关联对象
runtime的常见使用场景
1、动态变量控制
|
|
2、动态添加方法
|
|
3、动态交换两个方法的实现
|
|
4、拦截并替换方法
|
|
5、在方法上增加额外功能
|
|
这里拓展了按钮的点击功能,点击时新增了点击次数计算
6、实现NSCoding的自动归档和解档
|
|
7、实现字典转模型的自动转换
|
|