iOS-底層原理 04:NSObject的alloc 源碼分析

iOS 底層原理 文章匯總

主要NSObject中的alloc是與自定義類的alloc源碼流程的區(qū)別,以及為什么NSObject中的alloc不走源碼工程。

上一篇文章中分析了alloc的源碼,這篇文章是作為對(duì)上一篇文章的補(bǔ)充,去探索為什么NSObject的alloc方法不走源碼工程。

NSObject的alloc無(wú)法進(jìn)入源碼的問(wèn)題

  • 首先在objc4-781可編譯源碼中的main函數(shù)中增加一個(gè)NSObject定義的對(duì)象,NSObject 和 LGPersong同時(shí)加上斷點(diǎn)


    image
  • alloc的源碼實(shí)現(xiàn)中加一個(gè)斷點(diǎn),同時(shí)需要暫時(shí)關(guān)閉斷點(diǎn)

    image

  • 運(yùn)行target,斷點(diǎn)斷在NSObject部分,打開(kāi)alloc源碼的斷點(diǎn),然后繼續(xù)執(zhí)行,會(huì)出現(xiàn)以下這種現(xiàn)象

    image

探索Why

【第一步】探索[NSObject alloc]走的是哪步源碼

接下來(lái),我們就來(lái)探索為什么NSObject的alloc會(huì)出現(xiàn)這種情況,首先,

  • 打開(kāi)Debug --> Debug Workflow --> 勾選 Always Show Disassemly,開(kāi)啟匯編調(diào)試

  • 關(guān)閉源碼的斷點(diǎn),只留main中的斷點(diǎn),重新運(yùn)行程序,然后通過(guò)下圖的匯編可以發(fā)現(xiàn)NSObject并沒(méi)有走 alloc源碼,而是走的objc_alloc

    image

  • 然后關(guān)閉匯編調(diào)試,在全局搜索 objc_alloc,在objc_alloc中加一個(gè)斷點(diǎn),先暫時(shí)關(guān)閉,

    image

  • 重新運(yùn)行進(jìn)行調(diào)試,斷住,然后打開(kāi)objc_alloc的斷點(diǎn),發(fā)現(xiàn)會(huì)進(jìn)入objc_alloc的源碼實(shí)現(xiàn),此時(shí)查看 clsNSObject

    image

【第二步】探索 NSObject 為什么走 objc_alloc?

首先,我們來(lái)看看 NSObject 與 LGPerson的區(qū)別

  • NSObject 是iOS中的基類,所有自定義的類都需要繼承自NSObject
  • LGPerson繼承NSObject類的,重寫NSObject中的alloc方法

然后根據(jù)第一步中匯編的顯示,可以看出,NSObjectLGPerson 都調(diào)用了objc_alloc,所以這里就有兩個(gè)疑問(wèn)

  • 為什么NSObject 調(diào)用alloc方法 會(huì)走到 objc_alloc 源碼?
  • 為什么LGPerson中的alloc 會(huì)走兩次?即調(diào)用了alloc,進(jìn)入源碼,然后還要走到 objc_alloc?

LGPerson中alloc 走兩次 的 Why?

  • 首先,需要在源碼中調(diào)試,在mainLGPerson加斷點(diǎn),斷在LGPerson,再在allocobjc_alloccalloc 源碼加斷點(diǎn),運(yùn)行demo,會(huì)斷在objc_alloc源碼中(重新運(yùn)行前需要暫時(shí)關(guān)閉源碼中的所有斷點(diǎn))

    image

  • 繼續(xù)運(yùn)行,發(fā)現(xiàn)LGPerson 第一次的alloc會(huì)走到 objc_alloc --> callAlloc方法中最下方的objc_msgSend,表示向系統(tǒng)發(fā)送消息

    image

  • 繼續(xù)執(zhí)行代碼,發(fā)現(xiàn)會(huì)走到 alloc --> callAlloc --> _objc_rootAllocWithZOne,也就是iOS-底層原理 02:alloc & init & new 源碼分析源碼分析中的alloc流程.

以下是第二次走到calloc方法中的調(diào)用堆棧情況


image

所以由上述調(diào)試過(guò)程可以得出,LGPerson兩次的原因是首先需要去查找sel,以及對(duì)應(yīng)的imp的關(guān)系,當(dāng)前需要查找的是 alloc 的方法編號(hào),但是為什么會(huì)找到objc_alloc?這個(gè)就需要問(wèn)系統(tǒng)了,肯定是系統(tǒng)在底層做了一些操作。請(qǐng)接著往下看

NSObject中alloc 走到 objc_alloc 的 why?

這部分需要通過(guò) LLVM源碼(即llvm-project) 來(lái)分析

準(zhǔn)備工作:首先需要一份llvm源碼

  • 在llvm源碼中搜索objc_alloc

    image

  • 搜索shouldUseRuntimeFunctionForCombinedAllocInit,表示版本控制

    image

  • 搜索tryEmitSpecializedAllocInit,非常著名的特殊消息發(fā)送,在這里也沒(méi)有找到 objc_alloc

    image

  • 繼續(xù)嘗試,開(kāi)啟上帝視角,通過(guò)alloc字符串搜索,如果還找不到,還可以通過(guò)omf_alloc:找到tryGenerateSpecializedMessageSend,表示嘗試生成特殊消息發(fā)送

    image

    然后在這個(gè)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 會(huì)走到 objc_alloc,其實(shí)這部分是由系統(tǒng)級(jí)別的消息處理邏輯,所以NSObject的初始化是由系統(tǒng)完成的,因此也不會(huì)走到alloc的源碼工程中

總結(jié)

總結(jié)下NSObject中alloc 和自定義類中alloc的調(diào)用流程

NSObject

NSObject alloc源碼流程

自定義類

自定義類 alloc源碼流程
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。