主要 NSObjec 中的 alloc 和自定義類的 alloc的源碼流程區(qū)別,以及為什么NSObject 的 alloc 不走源碼工程
在上一篇文章中分析了 alloc 源碼,這篇文章是對(duì)上一篇的補(bǔ)充,去探索為什么 NSObject 的 alloc 不走源碼工程
NSObject的 alloc 無法進(jìn)入源碼的問題
-
首先在源碼工程的 main 中添加一個(gè) NSObject 和 SATest,同時(shí)加上斷點(diǎn)
image.png -
在 alloc 源碼實(shí)現(xiàn)中同時(shí)加上一個(gè)斷點(diǎn),同時(shí)需要暫時(shí)關(guān)閉斷點(diǎn)
image.png -
運(yùn)行 target,斷點(diǎn)斷在 NSObject 部分,同時(shí)打開 alloc 源碼部分?jǐn)帱c(diǎn),然后繼續(xù)執(zhí)行,會(huì)出現(xiàn)以下情況
33333.gif
探索原因
第一步:探索 NSObject 的 alloc 到底走哪一步源碼
- 打開匯編模式調(diào)試 Debug -> Debug workflow -> Always Show Disassembly
-
關(guān)閉源碼中所有的斷點(diǎn),只留 main 中的斷點(diǎn),重新運(yùn)行程序,通過匯編可以發(fā)現(xiàn)NSObject并沒有走 alloc 源碼,而是走的objc_alloc
image.png -
然后關(guān)閉匯編調(diào)試,在全局搜索objc_alloc,在objc_alloc處下斷點(diǎn),先暫時(shí)關(guān)閉
image.png -
重新運(yùn)行調(diào)試,斷住,然后重新打開 objc_alloc 的斷點(diǎn),發(fā)現(xiàn)會(huì)進(jìn)入 objc_alloc的源碼實(shí)現(xiàn),此時(shí)查看 cls 是 NSObject
image.png
第二步:探索 NSObject 為什么會(huì)走objc_alloc
首先我們先看看 NSObject 和 SATest 的區(qū)別
- NSObject 是ios 中的基類,所有自定義的類都需要集成自 NSObject
- SATest 是繼承自 NSObject 的,重寫了NSObject 中的 alloc 方法
根據(jù)匯編中的顯示,可以看出,NSObject 和 SATest 都調(diào)用了objc_alloc,所以就產(chǎn)生了兩個(gè)疑問, - 為什么 NSObject 調(diào)用 alloc 方法,會(huì)走到 objc_alloc方法源碼?
- 為什么 SATest中的 alloc 會(huì)走兩次?既調(diào)用了 alloc,進(jìn)入源碼,還要走到 objc_alloc?
SATest中的 alloc為什么會(huì)走兩次
-
首先,需要在源碼中調(diào)試,在 main 中的 SATest 處加斷點(diǎn),斷在 SATest,再在 alloc,objc_alloc,callAlloc 處加上斷點(diǎn),運(yùn)行 demo 會(huì)斷在 objc_alloc源碼中(重新運(yùn)行前,需要關(guān)閉所有斷點(diǎn))
image.png -
繼續(xù)運(yùn)行,發(fā)現(xiàn)第一次會(huì)走 objc_alloc -> callAlloc 中最下面的消息發(fā)送方法
image.png -
繼續(xù)執(zhí)行,發(fā)現(xiàn)會(huì)走alloc -> callAlloc -> _objc_rootAllocWithZone也就是第二篇中 alloc 流程
以下是第二次走到 callAlloc 方法中的調(diào)用堆棧情況
image.png
由上面描述可以得出,SATest 走兩次的原因是首先去查找 sel,以及對(duì)應(yīng)的 IMP 的關(guān)系,當(dāng)前需要查找的是 alloc 方法編號(hào),但是為什么會(huì)找到 objc_alloc,請(qǐng)往下看
NSObject 中的 alloc 為什么會(huì)走到 objc_alloc
需要通過 llvm源碼來分析源碼地址 -
在 llvm 源碼中搜索objc_alloc
image.png -
搜索shouldUseRuntimeFunctionForCombinedAllocInit,表示版本控制
image.png -
搜索tryEmitSpecializedAllocInit,著名的特殊消息發(fā)送,也沒找到 objc_alloc
image.png 繼續(xù)嘗試,開啟上帝視角,搜索 alloc 字符串,如果還是找不到,可以通過omf_alloc
找到tryGenerateSpecializedMessageSend-
然后在這個(gè) case 里面就可以找到調(diào)用 alloc,轉(zhuǎn)而調(diào)用 objc_alloc的邏輯,其中關(guān)鍵代碼是EmitObjCAlloc
image.png -
跳轉(zhuǎn)到EmitObjCAlloc方法,可以看到alloc 的處理是調(diào)用了 objc_alloc
image.png
由此可以得出NSObject 中的 alloc會(huì)走到 objc_alloc,其實(shí)這部分是由系統(tǒng)級(jí)別的消息發(fā)送處理,所以 NSObject的初始化是由系統(tǒng)完成的,因此不會(huì)走源碼工程
NSObjet 中源碼的調(diào)用流程

自定義類的源碼調(diào)用流程














