不管一个类设计的多么完美,在将来的需求演进中,都有可能会碰到一些没法预测的状况。那怎么扩展已有的类呢?通常而言,继承和组合是不错的选择。可是在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;,