一、作用
- 減少單個(gè)文件體積,把不同功能整合到不同的Category中;
- 可以按需加載;
- 聲明私有方法;
- 把framework的私有方法公開;
這是Category數(shù)據(jù)結(jié)構(gòu)
struct category_t {
const char *name; / /分類名
classref_t cls; / /分類所屬類的類名
struct method_list_t *instanceMethods; / /實(shí)例方法列表
struct method_list_t *classMethods; / /類方法列表
struct protocol_list_t *protocols; / /分類所實(shí)現(xiàn)協(xié)議列表
struct property_list_t *instanceProperties; / /實(shí)例屬性列表(可以添加屬性,但是不能添加實(shí)例變量,不要混淆實(shí)例變量和屬性)
// Fields below this point are not always present on disk.
struct property_list_t *_classProperties; / /類屬性
method_list_t *methodsForMeta(bool isMeta) {
if (isMeta) return classMethods;
else return instanceMethods;
}
property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};
Category底層原理探索
編譯期:存放到mach-o可執(zhí)行文件('_ DATA, _objc_const'標(biāo)識(shí)),以及方法_method_list_t

分類編譯成結(jié)構(gòu)體.png

_method_list_t結(jié)構(gòu)體詳細(xì)內(nèi)容.png

所有分類都存儲(chǔ)到_ _objc_catlist字段.png
運(yùn)行期:加載分類,首先了解如下
- dyld是蘋果的動(dòng)態(tài)加載器,用來加載 image(注意這里 image 不是指圖片,而是 Mach-O 格式的二進(jìn)制文件)。
- 當(dāng)程序啟動(dòng)時(shí),系統(tǒng)內(nèi)核首先會(huì)加載 dyld , 而 dyld 會(huì)將我們 APP 所依賴的各種庫加載到內(nèi)存空間中,其中就包括 libobjc 庫(OC和runtime), 這些工作,是在 APP 的 main 函數(shù)執(zhí)行前完成的。
- objc_init 是Object-C runtime 的入口函數(shù),在這里面主要功能是讀取 Mach-O 文件 OC 對(duì)應(yīng)的 Segment seciton ,并根據(jù)其中的數(shù)據(jù)代碼信息,完成為 OC 的內(nèi)存布局,以及初始化 runtime 相關(guān)的數(shù)據(jù)結(jié)構(gòu)。
image.pngmap_image-通過之前的標(biāo)識(shí) _objc_catlist加載到當(dāng)前原類,把類和分類建立關(guān)聯(lián),將分類里的方法或者屬性添加到原類,通過remethodizeClass(修改method_list的結(jié)構(gòu))布局重新排列,重點(diǎn)方法:objc初始化.pngimage.png下圖用memmove和memcpy都可以image.png但是這里的話,用memmove會(huì)更安全(首先拷貝的時(shí)候會(huì)一個(gè)一個(gè)拷貝,拷貝前兩個(gè)沒有問題,當(dāng)拷貝第三個(gè)的時(shí)候,值可能已經(jīng)變了,因?yàn)榭截惖谝粋€(gè)的時(shí)候已經(jīng)放在了第三的位置,所以可能會(huì)出現(xiàn)問題)image.pngimage.png
關(guān)聯(lián)對(duì)象
AssociationsManager管理hashMap,hashMap管理AssociationMap,屬性最終存儲(chǔ)在ObjcAssociation中image.png那我們關(guān)聯(lián)的對(duì)象是什么時(shí)候釋放的?是原對(duì)象銷毀的時(shí)候image.pngimage.png
load方法探索
調(diào)用規(guī)則
1.一個(gè)類的load方法在所有父類load方法調(diào)用之后調(diào)用;
2.分類的load方法在當(dāng)前類的load方法調(diào)用之后調(diào)用;(這里不分父類的分類和子類的分類,是所有分類)
3.分類load的調(diào)用順序和編譯順序有關(guān);
load方法調(diào)用(load_images)
prpare_load_methods:
從Macho文件加載類的列表,調(diào)整類的順序
最終得到存放類和分類的兩個(gè)容器;image.png
call_load_methods:先調(diào)用類容器 loadable_classes 后調(diào)用loadable_category(與上面類和分類load調(diào)用順序就呼應(yīng)上了)image.png
Category和extension(擴(kuò)展)
1.都可以添加屬性、方法,但是category無法生成實(shí)例變量;(
原則上,category只能添加方法,可利用runtime解決setter/getter問題);
2.extension在編譯時(shí)添加到類,category在運(yùn)行時(shí)添加到類(所以category中的方法沒實(shí)現(xiàn),編譯器沒有警告--另外編譯期對(duì)象內(nèi)存布局已經(jīng)確定,在運(yùn)行期添加變量,會(huì)破壞布局);
3.定義在 .m 文件中的類擴(kuò)展方法為私有的,定義在 .h 文件(頭文件)中的類擴(kuò)展方法為公有的。總結(jié)











