runtime 运行时机制(详情)
1 是什么?
runtime是一套比较底层的C语言API,属于一个C语言库,包含了很多底层的C语言API
平时编写的OC代码,在程序运行过程中,其实都是转成了runtime的C语言代码,runtime算是OC的幕后工作者
2 相关的头文件和函数
头文件:
12 <objc/runtime.h><objc/message.h>
3 特性
- 可以动态地创建类
- 动态的添加变量和属性,动态地遍历变量和属性
- 动态地添加方法,转化方法
4相关应用
methodSwizzling
比如公司项目后期突然提出新的需求要为所有页面添加统计功能,也就是用户进入这个页面就统计一次,
实现:给UIViewController写一个类别加到pch
类别中新建一个swillingViewDidLoad方法
在实现中,+(load)中运用runtime的method_exchangeImplementations替换掉系统的viewDidload方法和swillingViewDidLoad方法;
在swillingViewDidLoad方法中加入统计方法,然后调用swillingViewDidLoad方法
这样,当controller调用viewDidload时通过运行时,指向了自定义的swillingViewDidLoad,在这个方法里先执行了我们的统计方法,然后调用swillingViewDidload方法,指向系统的viewDidload方法,这样就实现了在每个类viewDidload前进行统计的操作。
还有数组越界,给系统的NSArray 替换一个自定义objectAtIndex
动态地给Category 添加属性详情
分类里面不能添加Ivar是因为分类本身并不是一个真正的类,它并没有自己的ISA。有兴趣可以研究一下类是怎么被创建出来的,类最开始生成了很多基本属性,比如IvarList,MethodList,分类只会将自己的method attach到主类,并不会影响到主类的IvarList。这就是为什么分类里面不能增加成员变量的原因。
runtime中的category
所有的关联对象都由AssociationsManager管理,而AssociationsManager定义如下:
|
|
AssociationsManager里面是由一个静态AssociationsHashMap来存储所有的关联对象的。这相当于把所有对象的关联对象都存在一个全局map里面。而map的的key是这个对象的指针地址(任意两个不同对象的指针地址一定是不同的),而这个map的value又是另外一个AssociationsHashMap,里面保存了关联对象的kv对。
|
|
runtime的销毁对象函数objc_destructInstance里面会判断这个对象有没有关联对象,如果有,会调用_object_remove_assocations做关联对象的清理工作。
NSCoding详情
归档和解档,利用runtime遍历模型对象的所有属性,写成宏文件
字典 –> 模型
利用runtime遍历模型对象的所有属性,根据属性名从字典中取出对应的值,设置到模型的属性上
KVO(原理)详情介绍
利用runtime动态产生一个类
消息转发
当我们像一个对象发送消息[Receiver message],Receiver没有实现该消息,即[Receiver respondsToSelector:SEL]返回为NO情况下,其实系统不会立刻出现crash,这时Runtime system会对message进行转发。转发之后,如果该消息依然没有被执行就会出现Crash!Runtime System为我们提供了三种解决这种给对象发送没有实现消息方案。
- 动态方法解析+ (BOOL)resolveInstanceMethod:(SEL)sel
- 备用接收者 - (id)forwardingTargetForSelector:(SEL)aSelector
- 完整转发 - (void)forwardInvocation:(NSInvocation *)anInvocation
用于封装框架(想怎么改就怎么改)
万能界面跳转
相关函数
- objc_msgSend :给对象发送消息
- class_copyMethodList: 遍历某个类所有的方法
- class_copyIvarList: 遍历某个类所有的成员变量