分类(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的加载影响程序的启动,因此需要合理运用分类,如果过度使用,会增加程序启动时间,影响用户体验。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END