1.概念:Category是Objective-C 2.0 之后添加的語言特性,它可以為已經(jīng)存在的類添加方法
2.作用:
2.1:可以減少單個文件的體積
2.2.可以把不同的功能組織到不同的 Category 中
2.3.可以按需加載
2.4.聲明私有方法
2.5.把 framework 的私有方法公開
3.源碼:源碼鏈接:https://github.com/RetVal/objc-runtime
struct category_t {
? ? const char *name; // 類的名稱
? ? classref_t cls;//類對象,編譯時期沒有值
? ? struct method_list_t *instanceMethods;//實例方法
? ? struct method_list_t *classMethods;//類方法
? ? struct protocol_list_t *protocols;//協(xié)議
? ? struct property_list_t *instanceProperties;//實例屬性
? ? // 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);
};
4.Category和extension(擴展)的區(qū)別
4.1.extension:
類的一部分
編譯時期決定
隱藏類的私有屬性
對象的內(nèi)存布局已確定
4.2.Category:
運行時期
不能添加變量
5.category從編譯到運行時期的過程
5.1.編譯時期:創(chuàng)建一個category,通過命令:clang -rewirte-objc category.m,可以看到它被加載到了__DATA數(shù)據(jù)段的__objc_catlist中

5.2.運行時期調(diào)用順序:
5.2.1.dyld_start:dyld是蘋果的動態(tài)加載器,用來加載動態(tài)庫,其中包括libobjc(OC和runtime)
可以通過打符號斷點看到


5.2.2._objc_init:入口函數(shù),讀取Mach-o文件對應(yīng)的Segment section,并根據(jù)其中的數(shù)據(jù)代碼信息,完成為OC的內(nèi)存布局,以及初始化runtime相關(guān)的數(shù)據(jù)結(jié)構(gòu)
5.2.3.map_images:dyld將image(Mach-o格式的二進(jìn)制文件)加載進(jìn)內(nèi)存
5.2.4.load_images:dyld初始化image,load方法也在這個時候調(diào)用
5.2.5.umap_image:dyld將image移除內(nèi)存

5.2.6.read_image:讀取oc相關(guān)的section,通過讀取seciton段來進(jìn)行初始化

map_images_nolock函數(shù)中找到_read_images

5.2.7._getObjc2CategoryList:讀取__objc_catlist

5.2.8.addUnattachedCategoryForClass:把分類加載到類當(dāng)中

5.2.9.NXMapInsert:cats(Category)和cls(類)建立關(guān)聯(lián)
5.2.10.remethodizeClass:對當(dāng)前cls 的內(nèi)存布局進(jìn)行重新排列
5.2.11.attachCategories:把當(dāng)前的cats附加到cls中

5.2.12.prepareMethodLists:準(zhǔn)備當(dāng)前類的方法列表

5.2.13.attachLists:通過memmove和memcpy,把分類的方法添加到原來的方法列表當(dāng)中

6.總結(jié):
6.1.通過5.2.7_getObjc2CategoryList讀取__objc_catlist secition段記錄中所有的category,存放到category_t 數(shù)組中
6.2.依次讀取category_t數(shù)組
6.3.cat和cls進(jìn)行映射
6.4.通過remethodizeClass修改method_list結(jié)構(gòu),這里涉及到memove和memcpy
7.動態(tài)添加屬性
7.1.AssociationsManager中存放了一個map(AssociationsHashMap),map中的key是當(dāng)前對象地址的按位取反,value是一個迭代器,也是一個map,迭代器map中的key是自定義的標(biāo)識,value是ObjcAssociation(用戶自定義的,用來存儲當(dāng)前的關(guān)聯(lián)屬性
)


7.2.關(guān)聯(lián)對象的釋放是在源對象被銷毀時釋放(dealloc),通過對象的指針來釋放關(guān)聯(lián)對象,具體調(diào)用的是_object_remove_assocations中的ReleaseValue

8.load方法:
8.1.一個類的load方法在所有的父類都調(diào)用完之后調(diào)用
8.2.category的調(diào)用load方法在類的調(diào)用load方法之后調(diào)用
8.3.category之間的調(diào)用順序:通過dyld調(diào)整調(diào)用順序和編譯順序有關(guān)