RunTime探索
1、Runtime是什么?
Runtime是OC基于C、C++封装的运行时API。
2、方法的本质是什么?
Runtime底层在OC方法进行调用时,底层会编译为objc_msgSend进行调用,如下图所示
(Clang编译完毕后的方法调用)
(OC原方法)
由此我们可以看出,方法的底层调用为消息发送。
3、类的本质是什么?
同理通过上面的方法可以看出类在底层为
typedef struct objc_object User
(objc_objcet源码)
4、runtime如何通过方法名称查找到方法的?
方法分为两类(对象方法和类方法)
对象方法调用(获取当前类的实例)
((void (*)(id, SEL))(void *)objc_msgSend)((id)user, sel_registerName("run"));
类方法调用 (获取当前类)
((void (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("User"), sel_registerName("walk"));
找到对应的方法我们需要了解的是方法的存储,对象方法和类方法的存储是不一样的,对象方法存储在类中,类方法的存储是在元类中,元类对象的方法存在根元类中。对象本身是一个带isa指针的结构体,所以在像一个对象发送消息的时候,实际上是通过isa在对象的类别中找到对应的方法。下附isa走位流程图
由图可简易得知方法的查找顺序:
1、方法会在缓存表中进行查找是否有SEL对应的IMP,如果的查找到,直接通过函数指针IMP找到方法的具体实现,执行方法。
2、如果方法没有存在缓存表中,就会根据类对象的方法列表进行对应的匹配查找,如果查找成功,,如果没有找到,就会根据类对象的superclass指针查找父类,(重复上述1,2流程),直到找到NSObject。
3、如果依旧没有找到对应的方法实现,就会进行方法决议(method resolve)。首先判断object的类对象是否实现了resoloveinstaceMethod:放法,如果实现了,会进行调用,这时候我们可以动态添加SEL,之后会重新进行查找方法流程,如果没有实现该方法,就行进行消息转发。
消息转发如上图所示。
1、调用函数forwardingTargetForSelector,尝试找到一个能响应该消息的对象,如果找到转发给他,如果没有找到,进行下一步
2、调用methodSignaturForSelector,获取一个方法签名,如果获取不到,则直接调用doesNotRecognizeSelecton抛出异常。
3、调用forwardinvocation方法将第2获取到的方法签名包装为invocaiotn传入,进行自定义处理。
5、runtime的作用
通常我们使用runtime进行的操作有,方法的交换,方法异常的处理,关联对象,数据解析,动态页面等。