浅谈系列-分类的结构和加载时机

分类(category)

导语:通过之前对类的结构分析,我们知道类本质是一个结构体。今天我们来了解一下分类的结构和加载流程。

分类结构

  • 简单来说,分类也是结构体,独立于类,并不是直接把扩展的内容添加到类,而是创建了一个分类结构体把能扩展的都放到里面,在runtime运行期动态添加到类中。

创建一个类的分类,在终端cd到.m的目录,通过以下命令,可以导出一个c++的分类代码文件,搜索”category_t {“,可以知道分类的结构。

xcrun -sdk iphoneos -arch arm64 clang -rewrite-objc 分类名称.m

除此之外,可以直接查看runtime源码,在objc-runtime-new中可以查找到分类的结构,如下

  struct category_t {
   const char *name;
   classref_t cls;
   WrappedPtr<method_list_t, PtrauthStrip> instanceMethods;
   WrappedPtr<method_list_t, PtrauthStrip> classMethods;
   struct protocol_list_t *protocols;
   struct property_list_t *instanceProperties;
   // Fields below this point are not always present on disk.
   struct property_list_t *_classProperties;

   method_list_t *methodsForMeta(bool isMeta) {
       if (isMeta) return classMethods;
       else return instanceMethods;
   }

   property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
   
   protocol_list_t *protocolsForMeta(bool isMeta) {
       if (isMeta) return nullptr;
       else return protocols;
   }
}; 
复制代码
  • 分类结构
category_t 备注
name 类名
instanceMethods 对象方法列表
classMethods 类方法列表
protocols 协议列表
instanceProperties 属性列表

通过分类的结构图可以知道分类里面的实例方法,类方法,协议,成员变量都是通过一个结构体category_t保存的,在编译阶段跟主类是相对独立的。

注意:在分类结构体(category_t)里,并没有发现成员列表(ivars),可以看出分类默认是不允许添加成员变量的。

Category是如何加载到主类的

分类数据加载过程
1 . 通过runtime加载主类的所有Category的数据
2 . 把所有的Category的对象方法,类方法,属性,协议数据合并到一个大数组中
3 . 将大数组中的分类数据(方法,属性,协议),插入到主类当中

越是后面编译的Category的数据,放在数组的前面,分类数据在主类数据的前面。

实际加载数据时,如果分类有与主类一样的方法,会调用分类的方法。

如果不同分类有相同的方法,会调用后面参加编译分类的方法。

整个加载流程都是通过runtime完成的。

runtime的加载影响程序的启动,因此需要合理运用分类,如果过度使用,会增加程序启动时间,影响用户体验。

浅谈系列-OC对象创建出来到底是怎么样的呢

浅谈系列-OC方法调用到底是个什么流程

浅谈系列 – KVO&KVC到底是怎么样实现的

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享