對方法的探索,全篇分六個章節(jié)
五、消息查找流程(重點)
前言
這一章將會介紹消息的第一個流程——查找流程。
當(dāng)調(diào)用一個方法的時候,系統(tǒng)是從哪里找到這個方法的?
[toc]
5.1 lookUpImpOrForward 準(zhǔn)備條件
從源碼中可以看到,有一個 retry:,retry的意思是重試,那么可以猜測出來下面的才是正真的流程,那上面的內(nèi)容是什么呢?
retry上面的兩段代碼,_class_initialize 和 realizeClass,不是初始化就是準(zhǔn)備,可以猜測這里是一些變量的準(zhǔn)備條件
再往上面走,看到有一個 runtimeLock。lock(); 方法,而且還有很多注釋,說明這段代碼在這個方法里面有很重要的作用。仔細(xì)扒一扒這些注釋的含義,
-
注釋一:講了運行時鎖的作用,防止多線程發(fā)生資源搶奪
runtimeLock在isrealize和isInitialized檢查過程中被持有,以防止對并發(fā)實現(xiàn)的競爭。
-
注釋二:講了為什么要添加運行時鎖。舉了一個例子,在緩存中搜索方法的時候(讀操作),分類可以刷新緩存(寫操作),同時對一塊內(nèi)存進(jìn)行讀寫操作,它是受不了的。
runtimeLock在方法搜索過程中保持,使方法查找+緩存填充原子相對于方法添加。否則,可以添加一個類別,但是會無限期地忽略它,因為在代表類別的緩存刷新之后,緩存會用舊值重新填充。
繼續(xù)往上面走,有一個 return imp; 代碼。這個方法本來就是查找一個方法的,能 return 的話,說明這個方法找到了。這里的代碼很簡單,就是從緩存里面找到了方法。
有趣的是這段代碼的注釋--// Optimistic cache lookup(樂觀的緩存查找)。這就有意思了,什么叫樂觀的,我們程序員講究的是嚴(yán)謹(jǐn)?shù)模茨苷业揭床荒苷业?,既然是樂觀的,我們就不用去分析他了。
再往上面走就是一些變量的創(chuàng)建,沒什么好分析的。
到這里,我們對 lookUpImpOrForward 方法已經(jīng)分析了一半了,下面來看另外一半流程。
5.2 lookUpImpOrForward 查找流程
5.2.1 lookUpImpOrForward 流程圖

5.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);
- 如果在父類中找到方法,則將方法緩存到當(dāng)前類,下次可以直接從緩存取
- 跳到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、方法動態(tài)決議流程
_class_resolveMethod(cls,sel,inst);
6、消息轉(zhuǎn)發(fā)流程
imp = (IMP)_objc_msgForward_impcache;
5.3 總結(jié)
- 為什么分析
lookUpImpOrForward方法。 - 怎么分析
lookUpImpOrForward方法。 -
retry前做了什么事。 -
retry后的流程是什么樣的。 -
lookUpImpOrForward查找流程圖