美文网首页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