无论一个类设计的多么完美,在未来的需求演进中,都有可能会碰到一些无法预测的情况。那怎么扩展已有的类呢?一般而言,继承和组合是不错的选择。但是在objective-c 2.0中,又提供了category这个语言特性,可以动态地为已有类添加新行为。如今category已经遍布于objective-c代码的各个角落,从apple官方的framework到各个开源框架,从功能繁复的大型app到简单的应用,catagory无处不在。本文对category做了比较全面的整理,希望对读者有所裨益。
objective-c中类别特性的作用如下:
(1)可以将类的实现分散到多个不同文件或多个不同框架中(补充新的方法)。
(2)可以创建私有方法的前向引用。
(3)可以向对象添加非正式协议。
objective-c中类别特性的局限性如下:
(1)类别只能想原类中添加新的方法,且只能添加而不能删除或修改原方法,不能向原类中添加新的属性。
(2)类别向原类中添加的方法是全局有效的而且优先级最高,如果和原类的方法重名,那么会无条件覆盖掉原来的方法。
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;,
如对本文有疑问, 点击进行留言回复!!
灰色预测模型GM(1,1)的发展系数a=0或无限接近于0的时候预测的误差以及解决办法
网友评论