首先分类的底层结构如下,也有类名,比如(Person)、对象方法列表、类对象方法列表、协议列表
struct _class_t {
struct _class_t *isa;
struct _class_t *superclass;
void *cache;
void *vtable;
struct _class_ro_t *ro;
};
//分类的结构
struct _category_t {
const char *name;//类名名称
struct _class_t *cls;
const struct _method_list_t *instance_methods;//对象方法列表
const struct _method_list_t *class_methods;//类方法列表
const struct _protocol_list_t *protocols;//协议列表
const struct _prop_list_t *properties;//属性列表
};
1.Category的加载处理过程
1.通过Runtime加载某个类的所有Category数据
2.把加载的Category的数据,包括方法、属性、协议等数据,合并到一个大数组中
3.将合并后的Category数据(方法、属性、协议等数据),插入到类原来数据的前面
2.以实例方法列表举例
1> 首先原来的类中有个class_rw_t的结构体,包含了method_list_t列表,这个列表是一个二维数组,有可能 method_list_t *list =[[method1,method2,method3]]这样子。
2> Category中的方法列表同上,当Category(A)与Category(B)方法列表合并之后合并之后,有可能 method_list_t *all_list =[[Amethod1,Amethod2,Amethod3],[Bmethod1,Bmethod2,Bmethod3]]。
3> 合并之前原来类的数组会根据分类方法列表个数重新分配数组内存,也就是扩容,并将原来的一维方法列表移到数组最后。
4> 再通过(while index--){method = all_list[index]},往新数组中添加一维方法列表,因为是index--,所以是后编译的分类的方法先添加
最终可能这样 method_list_t *last_list =[[Bmethod1,Bmethod2,Bmethod3],[Amethod1,Alastmethod2,Amethod3],[method1,method2,method3]]。
3.总结
从这里可以看出如果不同分类包括主类中有相同的方法实现,那么主类肯定是最后调用的,优先调用的事后加载的分类中的方法。
4.注意
在class_rw_t结构体重有一个const class_ro_t *ro只读的属性,里边也存在一份方法列表、属性列表、成员变量,如果有分类数据合并,这里依然保持原来类的数据,这里的方法列表是一维的。