ios 底層原理 : NSObject的 alloc 源碼分析

主要 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)用流程


未命名文件.png

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


未命名文件-2.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容