iOS底層-分類的加載原理

分類的本質(zhì)

在main中定義LGperson的分類LG


圖1

探索分類的本質(zhì),有以下三種方式

【方式一】通過clang
【方式二】通過Xcode文檔搜索Category
【方式三】通過objc源碼搜索 category_t

方式一:通過clang
【方式一】clang -rewrite-objc main.m -o main.cpp 查看底層編譯,即 main.cpp,

其中分類的 類型是_category_t
分類的倒數(shù)第二個0,表示的是沒有協(xié)議,所以賦值為0

圖2

搜索struct _category_t,如下所示

其中有兩個method_list_t,分別表示實例方法 和 類方法


圖3

搜索CATEGORY_INSTANCE_METHODS_LGPerson,找到其底層實現(xiàn)

圖4

其中有3個方法,格式為:sel+簽名+地址,是method_t結(jié)構(gòu)體的屬性即key


圖5

搜索method_t,其中對應(yīng)關(guān)系如下
name 對應(yīng) sel
type 對應(yīng) 方法簽名
imp 對應(yīng) 函數(shù)地址


圖6

方式二:通過Xcode文檔搜索 Category

如果不會clang,可以通過Xcode文檔搜索 Category


圖8

方式三:通過objc源碼搜索 category_t

還可以通過objc源碼搜索category_t類型


圖9

總結(jié)

綜上所述,分類的本質(zhì) 是一個_category_t類型

有兩個屬性:name(類的名稱) 和 cls(類對象)

有兩個 method_list_t類型的方法列表,表示分類中實現(xiàn)的實例方法+類方法

一個protocol_list_t類型的協(xié)議列表,表示分類中實現(xiàn)的協(xié)議

一個prop_list_t類型的屬性列表,表示分類中定義的屬性,一般在分類中添加的屬性都是通過關(guān)聯(lián)對象來實現(xiàn)

需要注意的是,分類中的屬性是沒有set、get方法

分類的加載

前提:創(chuàng)建LGPerson的兩個分類:LGA、LGB

圖10

其中查看methodizeClass的源碼實現(xiàn),可以發(fā)現(xiàn)類的數(shù)據(jù)和 分類的數(shù)據(jù)是分開處理的,主要是因為在編譯階段,就已經(jīng)確定好了方法的歸屬位置(即實例方法存儲在類中,類方法存儲在元類中),而分類是后面才加進來的


圖11

其中分類需要通過attatchToClass添加到類,然后才能在外界進行使用,在此過程,我們已經(jīng)知道了分類加載三步驟的后面兩個步驟,分類的加載主要分為3步:

分類數(shù)據(jù)加載時機:根據(jù)類和分類是否實現(xiàn)load方法來區(qū)分不同的時機

attachCategories準備分類數(shù)據(jù)

attachLists將分類數(shù)據(jù)添加到主類中

分類的加載時機

下面我們來探索分類數(shù)據(jù)的加載時機,以主類LGPerson + 分類LGA、LGB 均實現(xiàn)+load方法為例

通過第二步數(shù)據(jù)準備反推第一步的加載時機

通過上一篇文章我們了解到,在走到attachCategories方法時,必然會有分類數(shù)據(jù)的加載,可以通過反推法查看 在什么時候調(diào)用attachCategories的,通過查找,有兩個方法中調(diào)用

load_categories_nolock方法中

圖12

addToClass方法中,這里經(jīng)過調(diào)試發(fā)現(xiàn),從來不會進到if流程中,除非加載兩次,一般的類一般只會加載一次


圖13

不加任何斷點,運行objc代碼,可以得出以下打印日志,通過日志可以發(fā)現(xiàn)addToClass方法的下一步就是load_categories_nolock方法就是加載分類數(shù)據(jù)

圖14

全局搜索load_categories_nolock的調(diào)用,有兩次調(diào)用

一次在loadAllCategories方法中

圖15

一次在_read_images方法中


圖16

但是經(jīng)過調(diào)試發(fā)現(xiàn),是不會走_read_images方法中的if流程的,而是走的loadAllCategories方法中的


圖17

全局搜索查看loadAllCategories的調(diào)用,發(fā)現(xiàn)是在load_images時調(diào)用的
圖18

通過堆棧信息分析

在attachCategories中加自定義邏輯的斷點,bt查看堆棧信息


圖19

所以綜上所述,該情況下的分類的數(shù)據(jù)加載時機的反推路徑為:attachCategories -> load_categories_nolock -> loadAllCategories -> load_images

而我們的分類加載正常的流程的路徑為:realizeClassWithoutSwift -> methodizeClass -> attachToClass ->attachCategories

其中正向和反向的流程如下圖所示:

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

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