7、Runtime(2)

46 阅读2分钟

Objective-C中调用方法的具体流程,简单定义一个类,创建一个实例方法

在main函数进行调用

经过编译,可以得到如下代码,本质上相当于调用了C语言的函数objc_msgSend

其中sel_registerName函数,就是@selector方法选择器底层的函数调用,可以通过打印,发现存储方法的地址是一样的

objc_msgSend的源码是通过汇编编写的,可以大幅度的提高效率,具体代码在objc-msg-arm64.s文件中进行查看。

其中ENTRY是入口END_ENTRY为结束部分,这两者之间为objc_msgSend的具体实现

其中b.le指令,指的是在满足条件时跳转到LNilOrTagged位置

其中p0寄存器为receiver消息接收者,判断p0寄存器是否小于等于0,如果为0则是空指针,跳转到LNilOrTagged之后会跳转到LReturnZero执行ret指令,ret指令相当于高级语言中的return。如果指针不为空则执行LGetIsaDone,其中CacheLookup进行缓存中查找。

查看CacheLookup可以发现,CacheLookup是一个宏

通过其中的注释信息可以看出,是进行查找缓存的操作

CacheHit:命中缓存,命中之后,调用方法或者返回一个imp(实现地址)

根据注释可以看出如果sel方法选择器等于0则跳转到Miss中,具体实现如下图所示,如果未命中缓存则,重新修改imp的地址,通过isa指针的地址减去偏移量获得新的地址

最后会执行到这个入口没有缓存的入口

通过MethodTableLookup,方法表进行查找。

MethodTableLookup仍然是一个宏,最后要跳转到_lookUpImpOrForward

最后可以看的获取实例方法调用的便是lookUpImpOrForward方法,去掉下划线便是C语言实现Runtime的获取方法

总结:消息发送部分,首先判断receiver是否为空,如果是则退出,不是则进入当前类对象的缓存进行查找,如果查找到方法则直接调用,查找结束,如果没有找到则会在

class_rw_t查找,通过search_method_list方法进行查找,如果找到了方法则,调用方法结束查找,并将方法进行缓存,如果没有找到,则通过_objc_msgSendSuper进入父类进行查找,直到没有父类为止,如果仍然没有找到则进入动态方法解析。

其流程图大致如下