不管一個類設計的多麼完美,在將來的需求演進中,都有可能會碰到一些沒法預測的狀況。那怎麼擴展已有的類呢?通常而言,繼承和組合是不錯的選擇。可是在Objective-C 2.0中,又提供了category這個語言特性,能夠動態地爲已有類添加新行爲。現在category已經遍及於Objective-C代碼的各個角落,從Apple官方的framework到各個開源框架,從功能繁複的大型APP到簡單的應用,catagory無處不在。本文對category作了比較全面的整理,但願對讀者有所裨益。 html
Objective-C中類別特性的做用以下:框架
(1)能夠將類的實現分散到多個不一樣文件或多個不一樣框架中(補充新的方法)。函數
(2)能夠建立私有方法的前向引用。佈局
(3)能夠向對象添加非正式協議。ui
Objective-C中類別特性的侷限性以下:this
(1)類別只能想原類中添加新的方法,且只能添加而不能刪除或修改原方法,不能向原類中添加新的屬性。spa
(2)類別向原類中添加的方法是全局有效的並且優先級最高,若是和原類的方法重名,那麼會無條件覆蓋掉原來的方法。 ssr
Objective-C 經過 Runtime 運行時來實現動態語言這個特性,全部的類和對象,在 Runtime 中都是用結構體來表示的,Category 在 Runtime 中是用結構體 category_t 來表示的,下面是結構體 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;
從category的定義也能夠看出category的可爲(能夠添加實例方法,類方法,甚至能夠實現協議,添加屬性)和不可爲(沒法添加實例變量)。指針
咱們將結合 runtime 的源碼探究下 Category 的實現原理。打開 runtime 源碼工程,在文件 objc-runtime-new.mm
中找到如下函數:
void _read_images(header_info **hList, uint32_t hCount) { ... _free_internal(resolvedFutureClasses); } // Discover categories. for (EACH_HEADER) { category_t **catlist = _getObjc2CategoryList(hi, &count); for (i = 0; i < count; i++) { category_t *cat = catlist[i]; Class cls = remapClass(cat->cls); if (!cls) { // Category's target class is missing (probably weak-linked). // Disavow any knowledge of this category. catlist[i] = nil; if (PrintConnecting) { _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with " "missing weak-linked target class", cat->name, cat); } continue; } // Process this category. // First, register the category with its target class. // Then, rebuild the class's method lists (etc) if // the class is realized. BOOL classExists = NO; if (cat->instanceMethods || cat->protocols || cat->instanceProperties) { addUnattachedCategoryForClass(cat, cls, hi); if (cls->isRealized()) { remethodizeClass(cls); classExists = YES; } if (PrintConnecting) { _objc_inform("CLASS: found category -%s(%s) %s", cls->nameForLogging(), cat->name, classExists ? "on existing class" : ""); } } if (cat->classMethods || cat->protocols /* || cat->classProperties */) { addUnattachedCategoryForClass(cat, cls->ISA(), hi); if (cls->ISA()->isRealized()) { remethodizeClass(cls->ISA()); } if (PrintConnecting) { _objc_inform("CLASS: found category +%s(%s)", cls->nameForLogging(), cat->name); } } } } // Category discovery MUST BE LAST to avoid potential races // when other threads call the new category code before // this thread finishes its fixups. // +load handled by prepare_load_methods() ... }
咱們能夠知道在這個函數中對 Category 作了以下處理:
(1)將 Category 和它的主類(或元類)註冊到哈希表中;
(2)若是主類(或元類)已實現,那麼重建它的方法列表;
Category的實現原理:
// 這裏大概就相似這樣子插入 newproperties->next = cls->data()->properties; cls->data()->properties = newproperties;,