主要NSObject中的alloc是與自定義類的alloc的源碼流程的區(qū)別,以及為什么NSObject中的alloc不走源碼工程。
在上一篇文章中分析了alloc的源碼,這篇文章是作為對上一篇文章的補(bǔ)充,去探索為什么NSObject的alloc方法不走源碼工程。
NSObject的alloc無法進(jìn)入源碼的問題
-
首先在objc4-781可編譯源碼中的main函數(shù)中增加一個NSObject定義的對象,NSObject 和 LGPersong同時加上斷點(diǎn)
image -
在
alloc的源碼實(shí)現(xiàn)中加一個斷點(diǎn),同時需要暫時關(guān)閉斷點(diǎn)
image -
運(yùn)行target,斷點(diǎn)斷在
NSObject部分,打開alloc源碼的斷點(diǎn),然后繼續(xù)執(zhí)行,會出現(xiàn)以下這種現(xiàn)象
image
探索Why
【第一步】探索[NSObject alloc]走的是哪步源碼
接下來,我們就來探索為什么NSObject的alloc會出現(xiàn)這種情況,首先,
打開
Debug --> Debug Workflow --> 勾選 Always Show Disassemly,開啟匯編調(diào)試-
關(guān)閉源碼的斷點(diǎn),只留main中的斷點(diǎn),重新運(yùn)行程序,然后通過下圖的匯編可以發(fā)現(xiàn)
NSObject并沒有走alloc源碼,而是走的objc_alloc
image -
然后關(guān)閉匯編調(diào)試,在全局搜索
objc_alloc,在objc_alloc中加一個斷點(diǎn),先暫時關(guān)閉,
image -
重新運(yùn)行進(jìn)行調(diào)試,斷住,然后打開objc_alloc的斷點(diǎn),發(fā)現(xiàn)會進(jìn)入
objc_alloc的源碼實(shí)現(xiàn),此時查看cls是NSObject
image
【第二步】探索 NSObject 為什么走 objc_alloc?
首先,我們來看看 NSObject 與 LGPerson的區(qū)別
-
NSObject是iOS中的基類,所有自定義的類都需要繼承自NSObject -
LGPerson是繼承自NSObject類的,重寫了NSObject中的alloc方法
然后根據(jù)第一步中匯編的顯示,可以看出,NSObject 和 LGPerson 都調(diào)用了objc_alloc,所以這里就有兩個疑問:
- 為什么
NSObject調(diào)用alloc方法 會走到objc_alloc源碼? - 為什么
LGPerson中的alloc會走兩次?即調(diào)用了alloc,進(jìn)入源碼,然后還要走到 objc_alloc?
LGPerson中alloc 走兩次 的 Why?
-
首先,需要在源碼中調(diào)試,在
main中LGPerson加斷點(diǎn),斷在LGPerson,再在alloc、objc_alloc和calloc源碼加斷點(diǎn),運(yùn)行demo,會斷在objc_alloc源碼中(重新運(yùn)行前需要暫時關(guān)閉源碼中的所有斷點(diǎn))
image -
繼續(xù)運(yùn)行,發(fā)現(xiàn)
LGPerson第一次的alloc會走到objc_alloc --> callAlloc方法中最下方的objc_msgSend,表示向系統(tǒng)發(fā)送消息
image 繼續(xù)執(zhí)行代碼,發(fā)現(xiàn)會走到
alloc --> callAlloc --> _objc_rootAllocWithZOne,也就是iOS-底層原理 02:alloc & init & new 源碼分析源碼分析中的alloc流程.
以下是第二次走到calloc方法中的調(diào)用堆棧情況

所以由上述調(diào)試過程可以得出,LGPerson走兩次的原因是首先需要去查找sel,以及對應(yīng)的imp的關(guān)系,當(dāng)前需要查找的是 alloc 的方法編號,但是為什么會找到objc_alloc?這個就需要問系統(tǒng)了,肯定是系統(tǒng)在底層做了一些操作。請接著往下看
NSObject中alloc 走到 objc_alloc 的 why?
這部分需要通過 LLVM源碼(即llvm-project) 來分析
準(zhǔn)備工作:首先需要一份llvm源碼
-
在llvm源碼中搜索
objc_alloc
image -
搜索
shouldUseRuntimeFunctionForCombinedAllocInit,表示版本控制
image -
搜索
tryEmitSpecializedAllocInit,非常著名的特殊消息發(fā)送,在這里也沒有找到objc_alloc
image -
繼續(xù)嘗試,開啟上帝視角,通過
alloc字符串搜索,如果還找不到,還可以通過omf_alloc:找到tryGenerateSpecializedMessageSend,表示嘗試生成特殊消息發(fā)送
image
然后在這個case中可以找到調(diào)用alloc,轉(zhuǎn)而調(diào)用了objc_objc的邏輯,其中的關(guān)鍵代碼是EmitObjCAlloc
image -
跳轉(zhuǎn)至
EmitObjCAlloc的定義可以看到alloc的處理是調(diào)用了objc_alloc
image
由此可以得出 NSObject中的alloc 會走到 objc_alloc,其實(shí)這部分是由系統(tǒng)級別的消息處理邏輯,所以NSObject的初始化是由系統(tǒng)完成的,因此也不會走到alloc的源碼工程中
總結(jié)
總結(jié)下NSObject中alloc 和自定義類中alloc的調(diào)用流程
NSObject

自定義類














