类查找
先查找类中的方法然后再查找分类方法,分类中的方法会添加到类中的方法列表后面
lookUpImpOrForward
- 以下通过断点调试的方式进行查找
当对象调用方法时会调用objc_msgSend
中先进行判断在缓存中是否存在,如果不存在将会走到_objc_msgSend_uncached
未缓存中查找
objc_msgSend
此时我们使用断点进入就可以看到,进入objc_msgSend_uncached
中时调用了lookUpImpOrForward
方法,全局搜索lookUpImpOrForward
方法可以知道该方法是一个C++方法,可以查到具体的实现,此时我们就知道在调用objc_msgSend
后主要现在该方法中进行了方法的判断处理。
objc_msgSend
查找思路:查找方式是什么,条件是什么,,返回什么?
- 查找方式是什么?
lookUpImpOrForward()
在lookUpImpOrForward
方法中,首先调用一个_objc_msgForward_impcache
方法,通过调试汇编进行查找可以找到 __objc_msgForward
是在缓存中逐级进行消息转发找到一个目标进行处理,然后初始化一个临时的`imp = nil; Class = curClass;
lookUpImpOrForward()
lookUpImpOrForward()
当函数调用走到该判断语句时,需要解释一个behavior
参数,通过汇编可以看到参数 behavior
是通过LOOLUP_INITIALIZE = 1
与 LOOKUP_RESOLVER = 2
通过|
按位或的方式进行获得,此时behavior
的值为3
。
而
LOOKUP_CACHE = 4
,因此此时不会进入缓存中进行快速查找,接下来是对条件的一些判断比如类的初始化等此处略过。
内存查找
首先调用了
Method meth = getMethodNoSuper_nolock()
,该方法的主要作用是通过二分查找的方式在当前类的方法列表中进行二分查找,主要用到的方法如下getMethodNoSuper_nolock()
因为objc_class
中的class_data_bits_t bits
中的class_rw_t data
包含了类的属性
,方法
和协议
,所以可以调用相关方法来获取当前类的全部实例方法。
在该方法中就是通过使用指针来进行二分查找,在当前的方法列表中进行查找。
如果查找到了,把找到的函数指针地址给到当前临时变量imp
,并走到
done:
log_and_file_cache(cls, imp, sel, inst, curClass);
通过内部的调用cache_t
中的insert
方法,把当前方法插入到缓存的适当位置,至于是如何插入的,缓存是如何分配的可以查看cache_t讲解。
如果内有找到将进行在父类中逐级查找的方式进行查找,如果最后找到根类NSObject
还是没有找到,将把forward_imp
赋值给imp
来进行消息转发。
在这段代码中
LOOKUP_RESOLVER = 2
,调用resolveMethod_locked
方法resolveMethod_locked
然后就是在
resolveInstanceMethod
方法中进行处理。此时我们就可以重写
resolveInstanceMethod
方法,在该方法中为未实现的函数进行设置目标对象和函数。如果没有进行处理将进行消息转发。
消息转发流程
消息转发流程扩展
- 在进行二分查找时是优先在分类中查找而不是在本类中
网友评论