标签:
Category的使用场景主要有3个:
给现有的类添加方法;
将一个类的实现拆分成多个独立的源文件;
声明私有的方法。
实现原理:
我们知道,无论我们有没有主动引入 Category 的头文件,Category 中的方法都会被添加进主类中。我们可以通过 - performSelector: 等方式对 Category 中的相应方法进行调用,之所以需要在调用的地方引入 Category 的头文件,只是为了“照顾”编译器同学的感受。
打开 objc-runtime-new.mm 文件,可以找到 _read_images ()方法
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做了如下处理:
将 Category 和它的主类(或元类)注册到哈希表中;
如果主类(或元类)已实现,那么重建它的方法列表。
在这里分了两种情况进行处理:Category 中的实例方法和属性被整合到主类中;而类方法则被整合到元类中。另外,对协议的处理比较特殊,Category 中的协议被同时整合到了主类和元类中。
最终都是通过调用
remethodizeClass(Class cls)
这个函数的主要作用是将 Category 中的方法、属性和协议整合到类(主类或元类)中,更新类的数据字段 data() 中 method_lists(或 method_list)、properties 和 protocols 的值。进一步,我们通过 attachCategoryMethods 函数的源码可以找到真正处理 Category 方法的 attachMethodLists 函数。
它的主要作用就是将集中的久类方法和Category中新添加的方法整合成一个心的方法列表,并赋值给 method_lists 或者 method_list 。说明了:主类中的方法和Category中的方法在runtime看来并没有区别,它们是被同等对待的,都保存在主类的方法列表中。
runtime 对 Category 中方法的处理过程并没有对 +load 方法进行什么特殊地处理。因此,严格意义上讲 Category 中的 +load 方法跟普通方法一样也会对主类中的 +load 方法造成覆盖,只不过 runtime 在自动调用主类和 Category 中的 +load 方法时是直接使用各自方法的指针进行调用的。所以才会使我们觉得主类和 Category 中的 +load 方法好像互不影响一样。因此,当我们手动给主类发送 +load 消息时,调用的一直会是分类中的 +load 方法。
Objective-C 源码(三)Category的实现原理
标签:
原文地址:http://my.oschina.net/caijunrong/blog/529417