RunTime
什么是runtime?
Runtime库主要做下面几件事:
- 封装:在这个库中,对象可以用C语言中的结构体表示,而方法可以用C函数来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
- 找出方法的最终执行代码:当程序执行[object doSomething]时,会向消息接收者(object)发送一条消息(doSomething),runtime会根据消息接收者是否能响应该消息而做出不同的反应。这将在后面详细介绍。
- RunTime简称运行时。OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
- 对于C语言,函数的调用在编译的时候会决定调用哪个函数。
- 对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
- 事实证明:
- 在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错。
- 在编译阶段,C语言调用未实现的函数就会报错。
我们写的oc代码,它在运行的时候也是转换成了runtime方式运行的,更好的理解runtime,也能帮我们更深的掌握oc语言。 每一个oc的方法,底层必然有一个与之对应的runtime方法。
当我们用OC写下这样一段代码 [tableView cellForRowAtIndexPath:indexPath];
在编译时RunTime会将上述代码转化成[发送消息] objc_msgSend(tableView, @selector(cellForRowAtIndexPath:),indexPath);
常用的头文件
#import <objc/runtime.h> 包含对类、成员变量、属性、方法的操作
#import <objc/message.h> 包含消息机制
常用方法
class_copyIvarList()返回一个指向类的成员变量数组的指针
class_copyPropertyList()返回一个指向类的属性数组的指针
注意:根据Apple官方runtime.h文档所示,上面两个方法返回的指针,在使用完毕之后必须free()。
ivar_getName()获取成员变量名-->C类型的字符串
property_getName()获取属性名-->C类型的字符串
-------------------------------------
typedef struct objc_method *Method;
class_getInstanceMethod()
class_getClassMethod()以上两个函数传入返回Method类型
---------------------------------------------------
method_exchangeImplementations()交换两个方法的实现
常见作用
动态的添加对象的成员变量和方法
动态交换两个方法的实现
拦截并替换方法
在方法上增加额外功能
实现NSCoding的自动归档和解档
实现字典转模型的自动转换
代码实现
要使用runtime,要先引入头文件#import 这些代码的实例有浅入深逐步讲解,最后附上一个我在公司项目中遇到的一个实际问题。
1. 动态变量控制
在程序中,xiaoming的age是10,后来被runtime变成了20,来看看runtime是怎么做到的。
- 动态获取XiaoMing类中的所有属性[当然包括私有]
Ivar *ivar = class_copyIvarList([self.xiaoming class], &count);
- 遍历属性找到对应name字段
const char *varName = ivar_getName(var);
- 修改对应的字段值成20
object_setIvar(self.xiaoMing, var, @"20");
代码参考
-(void)answer{ unsigned int count = 0; Ivar *ivar = class_copyIvarList([self.xiaoMing class], &count); for (int i = 0; i2.动态添加方法