分類的本質(zhì)
在main中定義LGperson的分類LG

探索分類的本質(zhì),有以下三種方式
【方式一】通過clang
【方式二】通過Xcode文檔搜索Category
【方式三】通過objc源碼搜索 category_t
方式一:通過clang
【方式一】clang -rewrite-objc main.m -o main.cpp 查看底層編譯,即 main.cpp,
其中分類的 類型是_category_t
分類的倒數(shù)第二個0,表示的是沒有協(xié)議,所以賦值為0

搜索struct _category_t,如下所示
其中有兩個method_list_t,分別表示實例方法 和 類方法

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

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

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

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

方式三:通過objc源碼搜索 category_t
還可以通過objc源碼搜索category_t類型

總結(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

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

其中分類需要通過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方法中

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

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

全局搜索load_categories_nolock的調(diào)用,有兩次調(diào)用
一次在loadAllCategories方法中

一次在_read_images方法中

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

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

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

所以綜上所述,該情況下的分類的數(shù)據(jù)加載時機的反推路徑為:attachCategories -> load_categories_nolock -> loadAllCategories -> load_images
而我們的分類加載正常的流程的路徑為:realizeClassWithoutSwift -> methodizeClass -> attachToClass ->attachCategories
其中正向和反向的流程如下圖所示:
