美文网首页iOS底层知识iOS 面试专项
iOS分类的实现原理简记

iOS分类的实现原理简记

作者: 小千 | 来源:发表于2018-06-22 17:38 被阅读33次

    该文为分类原理的简单记录,总结自如下文章,感谢作者分享:


    1、分类的结构

    分类的结构体如下

    struct_category_t{
    
    constchar *name;//类名
    
    struct_class_t *cls;//分类所属的类
    
    //category中所有给类添加的实例方法的列表(instanceMethods)
    conststruct_method_list_t *instance_methods;
    
    //category中所有添加的类方法的列表(classMethods)
    conststruct_method_list_t *class_methods;
    
    //category实现的所有协议的列表(protocols)
    conststruct_protocol_list_t*protocols;
    
    //category中添加的所有属性(instanceProperties)
    conststruct_prop_list_t*properties;
    
    };
    

    2、分类的编译过程

    通过如下命令将分类的m文件进行转换,分析其编译过程

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xxx+xxx.m

    structcategory_t{
    
    constchar *name;// 类名
    
    classref_tcls; // 分类所属的类
    
    // 实例方法列表
    structmethod_list_t*instanceMethods;
    
    // 类方法列表
    structmethod_list_t*classMethods;
    
    // 遵循的协议列表
    structprotocol_list_t*protocols;
    
    // 属性列表
    structproperty_list_t*instanceProperties;
    
    // 如果是元类,就返回类方法列表;否则返回实例方法列表
    method_list_t*methodsForMeta(boolisMeta) {
    
    if(isMeta) {
    
      return classMethods; 
    
     }else{
    
      return instanceMethods;
    
     }
    
     }
    
    // 如果是元类,就返回 nil,因为元类没有属性;否则返回实例属性列表,关于分类的实例属性,下文阐述
    property_list_t*propertiesForMeta(boolisMeta) {
    
    if(isMeta) {
    
      return nil;// 元类没有属性;
    
    }else{
    
      return instanceProperties;//实例属性
    
     } 
    
     }
    
    };
    

    3、分类的实现原理:

    由上可得,分类在编译过程中,会生成 类方法列表实例方法列表属性列表 等,但是却 没有 实例变量列表(_ivar_list_t) ,可对比分类所属类的编译结果看,分类所属类是存在实例变量列表的。然后,再来对比 实例方法列表 ,还能发现分类的 实例方法列表 中,并未对分类属性生成 getter/setter 方法。

    所以,这就是为什么 分类不能添加属性 的原因。

    4、分类的加载

    • 分类是在 运行时 进行加载的,其加载调用栈如下:
    _objc_init   //runtime的初始化函数,进行初始化操作,注册了镜像状态改变时的回调函数
    
    └── map_2_images //加锁并调用 map_images_nolock
    
        └── map_images_nolock //完成所有 class 的注册、fixup等工作,还有初始化自动释放池、初始化 side table 等工作并在函数后端调用了 _read_images
    
            └── _read_images //加载类、Protocol、Category,加载分类的代码就写在 _read_images 函数的尾部
    

    _objc_init 函数在 objc-os.mm 中,_read_images 方法在objc-runtime-new.mm 中。

    • 加载过程:

    1、把分类的 实例方法属性协议 添加到类的实例对象中原本存储的 实例方法属性协议列表前面
    2、把分类的 类方法协议添加到类的元类上。

    如此,保证了分类方法 优先调用,注意,不是覆盖,而是共同存在在实例方法列表中,只是分类在前而已。

    相关文章

      网友评论

        本文标题:iOS分类的实现原理简记

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