美文网首页
Category 分类底层实现

Category 分类底层实现

作者: code_牧轩 | 来源:发表于2020-12-07 22:16 被阅读0次

    一:概念分析 

       1.分类和类公用一个类对象结构;

       2.分类的类方法存储到元类里面;

       3.分类的方法、协议、属性在运行时(runtime)合并到类对象中。

    二、编译期:

    分类生成的内存结构:

     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;//属性列表

     };

    实际例子如下:

         static struct _category_t _OBJC_$_CATEGORY_lzhPerson_$_test __attribute__ ((used, section ("__DATA,__objc_const"))) =

        {

         "lzhPerson",

         0, // &OBJC_CLASS_$_lzhPerson,

         (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_lzhPerson_$_test,

         0,

         (const struct _protocol_list_t *)&_OBJC_CATEGORY_PROTOCOLS_$_lzhPerson_$_test,

         (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_lzhPerson_$_test,

     };

    注:在分类编译期生成的结构中没有isa、superclass指针,以及没有ivar成员变量数组;

    三、运行期:

            1.通过runtime加载某个类的所有分类Category数据

            2.把所有分类Category的方法、属性、协议数据合并到一个二维数组中,二维数组的每一个元素(子数组)都是一个分类的对象的数据;

             后面参与编译的Category数据,会放在数组的前面(compile Soures 中的.m文件;下面先执行);    

           3.将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面;

    四、源码分析

      1._objc_init  运行时的一个入口

       2.map_images ->map_images_nolock()

       3._read_images(hList, hCount, totalClasses, unoptimizedTotalClasses); 加载镜像 在这个里面合并分类函数

       4.remethodizeClass 重新方法化;

       5.remethodizeClass(cls->ISA());重新方法化元类对象

        6.attachCategories(cls, cats, true flush caches); 合并方法。出入到类和分类列表;

        7. 生成方法、属性、协议二维数组列表;合并完成以后的二维数组如下图:

       method_list_t **mlists = (method_list_t **)  二维数组

         malloc(cats->count * sizeof(*mlists));

       property_list_t **proplists = (property_list_t **)

         malloc(cats->count * sizeof(*proplists));

       protocol_list_t **protolists = (protocol_list_t **)

         malloc(cats->count * sizeof(*protolists));

     mlists

     [

      [ method_t,method_t], 分类1

      [ method_t,method_t],分类2

      [ method_t,method_t],分类3

      ]

     proplists

      [

      [ property_t,method_t], 分类1 属性

      [  property_t,method_t],分类2属性

      [ property_t,method_t],分类3属性

      ]

       8.methods.attachLists  奖所有分类的方法、属性、协议附加到类对象的数组对象中

       9. 添加到类对象中:

          memmove(array()->lists + addedCount, array()->lists,  内存移动

                 oldCount * sizeof(array()->lists[0]));

         memcpy(array()->lists, addedLists,

                addedCount * sizeof(array()->lists[0]));  内存拷贝

    五、分类Category和扩展的extension的区别是:

    1.类扩展(extension)是category的一个特例,有时候也被称为匿名分类或者私有类。他的作用是为一个类添加一些私有的成员变量和方法。

    2.类扩展能写点啥?和分类不同,类扩展即可以声明成员变量又可以声明方法。

    3.类扩展听上去很复杂,但其实我们很早就认识他了。你记得继承自UIViewController的ViewController和继承自NSObject的类有什么不同么?

    4.类扩展可以定义在.m文件中,这种扩展方式中定义的变量都是私有的,也可以定义在.h文件中,这样定义的代码就是共有的,类扩展在.m文件中声明私有方法是非常好的方式。

    5.类扩展中添加的新方法,一定要实现。categorygory中没有这种限制。

    相关文章

      网友评论

          本文标题:Category 分类底层实现

          本文链接:https://www.haomeiwen.com/subject/giqxgktx.html