我的理解Runtime就是:
1)、一套用C/C++和汇编实现的一套API
OC就是运行时机制,其中最主要的是消息机制。
对于C语言,函数的调用在编译的时候会决定调用哪个函数;
对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
2)、OC 是一个全动态语言,OC 的一切都是基于 Runtime 实现的
平时编写的OC代码, 在程序运行过程中, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者
举例:
[[Person alloc] init]
runtime :
objc_msgSend(objc_msgSend("Person" , "alloc"), "init")
一、数据结构:
objc_object,objc_class,isa,class_data_bits_t,cache_t,method_t
objc_object(id)
isa_t:关于isa操作相关,弱引用相关,关联对象相关,内存管理相关
objc_class (class) :继承自objc_object
isa指向:
关于对象,其指向类对象。
关于类对象,其指向元类对象。
实例--(isa)-->class--(isa)-->MetaClass
cache_t:用于快速查找方法执行函数,是可增量扩展的哈希表结构,是局部性原理的最佳运用
method_t:
函数四要素:名称,返回值,参数,函数体
struct method_t {
SEL name; //名称
const char *types;//返回值和参数
IMP imp; //函数体
}
二、对象,类对象,元类对象
类对象存储实例方法列表等信息。
元类对象存储类方法列表等信息。
三、消息传递的流程:(如何通过selector找到对应的IMP地址)
缓存查找-->当前类查找-->父类逐级查找
1.调用方法之前,先去查找缓存,看看缓存中是否有对应选择器的方法实现,如果有,就去调用函数,完成消息传递(缓存查找:给定值SEL,目标是查找对应bucket_t中的IMP,哈希查找)
2.如果缓存中没有,会根据当前实例的isa指针查找当前类对象的方法列表,看看是否有同样名称的方法 ,如果找到,就去调用函数,完成消息传递(当前类中查找:对于已排序好的方法列表,采用二分查找,对于没有排序好的列表,采用一般遍历)
3.如果当前类对象的方法列表没有,就会逐级父类方法列表中查找,如果找到,就去调用函数,完成消息传递(父类逐级查找:先判断父类是否为nil,为nil则结束,否则就继续进行缓存查找-->当前类查找-->父类逐级查找的流程)
4.如果一直查到根类依然没有查找到,则进入到消息转发流程中,完成消息传递
举例:
下面以实例对象调用方法[blackDog walk]为例描述方法调用的流程
1)、编译器会把`[blackDog walk]`转化为`objc_msgSend(blackDog,SEL)`,SEL为@selector(walk)。
2)、Runtime会在blackDog对象所对应的Dog类的方法缓存列表里查找方法的SEL
3)、如果没有找到,则在Dog类的方法分发表查找方法的SEL。(类由对象isa指针指向,方法分发表即methodList)
4)、如果没有找到,则在其父类(设Dog类的父类为Animal类)的方法分发表里查找方法的SEL(父类由类的superClass指向)
5)、如果没有找到,则沿继承体系继续下去,最终到达NSObject类。
6)、如果在234的其中一步中找到,则定位了方法实现的入口,执行具体实现
7)、如果最后还是没有找到,会面临两种情况:``(1) 如果是使用`[blackDog walk]`的方式调用方法````(2) 使用`[blackDog performSelector:@selector(walk)]`的方式调用方法
四、消息转发:
1)、动态方法解析
接收到未知消息时(假设blackDog的walk方法尚未实现),runtime会调用+resolveInstanceMethod:(实例方法)或者+resolveClassMethod:(类方法)
2)、备用接收者
如果以上方法没有做处理,runtime会调用- (id)forwardingTargetForSelector:(SEL)aSelector方法。
如果该方法返回了一个非nil(也不能是self)的对象,而且该对象实现了这个方法,那么这个对象就成了消息的接收者,消息就被分发到该对象。
适用情况:通常在对象内部使用,让内部的另外一个对象处理消息,在外面看起来就像是该对象处理了消息。
比如:blackDog让女朋友whiteDog来接收这个消息
3)、完整消息转发
在- (void)forwardInvocation:(NSInvocation *)anInvocation方法中选择转发消息的对象,其中anInvocation对象封装了未知消息的所有细节,并保留调用结果发送到原始调用者。
比如:blackDog将消息完整转发給主人dogOwner来处理
五、应用
1、发送消息
方法调用的本质,就是让对象发送消息。
objc_msgSend,只有对象才能发送消息,因此以objc开头.
使用消息机制前提,必须导入#import <objc/message.h>
2、交换方法
3、类\对象的关联对象
4、动态添加方法
5、字典转模型KVC实现
网友评论