流程总结
1 void _read_images(header_info **hList, uint32_t hCount);
参数是个 header_info指针数组,应该有多个 header_info。遍历每个 header_info,取出指向 category_t结构体的指针数组(每个 category_t 是一个类目)
category_t **catlist = _getObjc2CategoryList(hi, &count);
2 再次循环,取出每个数组的元素,即指向 category_t的指针。类目中可以存在实例方法,也可以存在类方法。(实例方法,属性,协议 和类相关,而类方法协议与元类相关),分别处理与类,元类相关的。先处理 与类相关的
3 来到 addUnattachedCategoryForClass函数,通过 unattachedCategories得到NXMapTable * 我觉得这应该是全局的一张表,类似2.0之前的引用计数表。在这个表中通过cls,寻找对应的 category_list。这个结构体里面有个结构体数组,数组中存放的元素是category_t* 及与类目相关的头信息的结构体。然后将category_t与头信息构造成结构体,插入到category_list。
,
这里可以理解,在一张表存放着没有被处理的对应cls的list,list对应着cls,一个lists可以视为cats数组
4 然后来到 remethodizeClass函数,调用 unattachedCategoriesForClass,得到与cls相关的category_list,并将 cls与 category_list从 NXMapTable中删除。拿到 category_list就来到了attachCategories,这是个关键的方法,开始了处理。
5 构建method_list_t,property_list_t,protocol_list_t类型的指针数组,它们都是继承自entsize_list_tt。拿到传入的 category_list,遍历,取出每个category_t。在循环内取到 category_t的结构成员 method_list_t,property_list_t,protocol_list_t, method_list_t 自然存放着一个类目的实例方法,是method_t的list。
然后,将一个类目中每个 list的指针放入对应的指针数组(在这里,我们看到这个 category_list并不是存放着cls所有的类目,而是在上层循环内存取)循环结束。以 method_list_t为例,指针数组每个元素都是指向每个类目的实例方法数组的指针。传入的个数自然是数组的个数,也就是类目的个数。
6 然后拿到cls的rw(这个前面说过 objc_class的成员变量,读写属性,存储着 objc_class的方法,属性,协议。而这三个家伙 都是 method_array_t类型)取出三个变量,调用 method_array_t attachLists
这个函数,将 method_array_t的三种状态说明的淋漓尽致。函数的参数刚才的指针数组。函数内分为三种情况:
如果 method_array_t,没有 array,且添加的 list只有一个,那么直接 method_array_t的 list指向指针数组的唯一一个元素。也就是一个类目的方法列表
如果 method_array_t,没有 array,而添加的 list有多个,那么开辟空间,将指针数组元素拷贝到 lists数组,然后list有值,那么添加到数组最后(感觉说数组不合适,而是链表,地址并不连续)
如果 method_array_t,存 在array,那么扩充空间,新添加的元素们放在lists前,之前的元素放在后
也就是说cls->rw 的method_array_t 存放着一个类的方法,以指针数组或者指针的形式。如果是指针,则指向一个list*(方法列表),如果是数组是个指针数组,每个元素都是list*
我猜测这些动作发生在只读指针ro的方法,属性,协议添加到cw之后,因为,类目的方法会"覆盖"类中原有方法
上面是我读该方法的源码进行了分析,下面我们回到美团类目的源码分析。美团分析时的方法实现和现在的源码可能已经有些不同