对方法的探索,全篇分六个章节
五、消息查找流程(重点)
前言
这一章将会介绍消息的第一个流程——查找流程。
当调用一个方法的时候,系统是从哪里找到这个方法的?
[toc]
5.1 lookUpImpOrForward 准备条件
从源码中可以看到,有一个 retry:
,retry的意思是重试,那么可以猜测出来下面的才是正真的流程,那上面的内容是什么呢?
retry上面的两段代码,_class_initialize
和 realizeClass
,不是初始化就是准备,可以猜测这里是一些变量的准备条件
再往上面走,看到有一个 runtimeLock。lock();
方法,而且还有很多注释,说明这段代码在这个方法里面有很重要的作用。仔细扒一扒这些注释的含义,
-
注释一:讲了运行时锁的作用,防止多线程发生资源抢夺
runtimeLock在isrealize和isInitialized检查过程中被持有,以防止对并发实现的竞争。
-
注释二:讲了为什么要添加运行时锁。举了一个例子,在缓存中搜索方法的时候(读操作),分类可以刷新缓存(写操作),同时对一块内存进行读写操作,它是受不了的。
runtimeLock在方法搜索过程中保持,使方法查找+缓存填充原子相对于方法添加。否则,可以添加一个类别,但是会无限期地忽略它,因为在代表类别的缓存刷新之后,缓存会用旧值重新填充。
继续往上面走,有一个 return imp;
代码。这个方法本来就是查找一个方法的,能 return 的话,说明这个方法找到了。这里的代码很简单,就是从缓存里面找到了方法。
有趣的是这段代码的注释--// Optimistic cache lookup
(乐观的缓存查找)。这就有意思了,什么叫乐观的,我们程序员讲究的是严谨的,要么能找到要么不能找到,既然是乐观的,我们就不用去分析他了。
再往上面走就是一些变量的创建,没什么好分析的。
到这里,我们对 lookUpImpOrForward
方法已经分析了一半了,下面来看另外一半流程。
5.2 lookUpImpOrForward 查找流程
5.2.1 lookUpImpOrForward 流程图
image5.2.2 lookUpImpOrForward 流程分析
从 retry
开始分析
1、从类的缓存查找,如果找到IMP,则跳到Done,返回IMP
imp = cache_getImp(cls,sel);
2、从类的方法列表查找
Method meth = getMethodNoSuper_nolock(cls,sel);
- 查找算法:二分查找
- 如果找到,则填充缓存,跳到Done,返回IMP
log_and_fill_cache(cls,meth->imp,sel,inst,cls);
遍历父类
for (Class curClass = cls->superclass; curClass != nil; curClass = curClass->superclass)
3、从父类的缓存查找
imp = cache_getImp(curClass,sel);
- 如果在父类中找到方法,则将方法缓存到当前类,下次可以直接从缓存取
- 跳到Done,返回IMP
log_and_fill_cache(cls,imp,sel,inst,curClass);
4、从父类的方法列表查找
Method meth = getMethodNoSuper_nolock(curClass,sel);
- 查找算法:二分查找
- 如果找到,则填充缓存
- 跳到Done,返回IMP
log_and_fill_cache(cls,meth->imp,sel,inst,curClass);
5、方法动态决议流程
_class_resolveMethod(cls,sel,inst);
6、消息转发流程
imp = (IMP)_objc_msgForward_impcache;
5.3 总结
- 为什么分析
lookUpImpOrForward
方法。 - 怎么分析
lookUpImpOrForward
方法。 -
retry
前做了什么事。 -
retry
后的流程是什么样的。 -
lookUpImpOrForward
查找流程图
网友评论