參考文章美團技術博客
文章爲原創,轉載請註明出處
Category簡介
使用Category把類分開在幾個不同的文件裏,這樣做有幾個好處
- 減少單個文件體積
- 把不同的功能組織到不同的Category裏
- 可以由多個開發者共同完成一個類
- 可按需加載要用的Category
- Category還可以模擬多繼承,把frameWork的私有方法分開
- Category無法添加實例變量
Category 的結構
- Objective-C類和對象在runtime都是用結構體表示的,Category也一樣,在runtime層,Category使用category_t結構體
typedef struct category_t {
const char *name;
classref_t cls;
struct method_list_t *instanceMethods;
struct method_list_t *classMethods;
struct protocol_list_t *protocols;
struct property_list_t *instanceProperties;
} category_t;
其中包含了:
1. 類的名字
2. 類
3. category中添加的實例方法列表
4. category中添加的類方法列表
5. category中所實現的protocol表列
6. category中添加的屬性
從上面看出Category可以添加(實例方法,類方法,實現協議,添加屬性),不能添加實例變量
Category的加載
- Category是在runtime進入入口的時候添加到類上面的,runtime遍歷Category_t數組,將Category的實例方法,協議,屬性添加到類上,把Category的類方法添加到類的metaClass上面
- Category方法沒有“完全替換“原來類已有的方法,也就是說,如果Category添加了MethodA,原來的類也有同樣的方法,那麼該類此時有兩個MethodA方
- Category的方法被放到了新方法列表的前面,在runtime的objc_msgSend查找方法時,找到第一個方法就調用該方法,所以當多個Category重寫了同一個方法時,會使用編譯時放在後面的Category的方法
Category和+load方法
- Category可以覆寫類的+load方法,因爲類的+load發生在Category的+load方法之前,當多個Category都覆寫了+load方法時,Category的+load方法取決於Category文件的編譯順序
Category 和 關聯對象
由於Category中無法動態的添加實例變量,所以可以通過關聯對象的方法來爲類添加實例變量
關聯對象存儲在一個全局叫AssociationsManager的map裏,其中key是被關聯對象的指針地址,value存儲着另一個靜態的全局map,稱爲AssociationHashMap,這裏的key和value分別是設置關聯對象時候的Key和Value
class-continuation
- 不對外公開的方法和實例變量寫在"class-continuation"裏,class-continuation只能定義在類的實現文件裏
- 屬性和實例方法也可以定義在這裏,定義在這裏然後在依次實現會顯得明確一點
- 將public接口實現的只讀方法在這裏擴展成可讀寫方法,以便在內部設置其值,一般不直接訪問實例變量,通過設置方法來做,這樣可以觸發KVO
- 對象的協議方法只用設置爲私有時在class-continuation裏定義