一.Category的底层结构
在runtime运行中都是一个category_t的一个结构体,里面包含{
类名,
对象方法列表,
类方法列表,
协议,
实例化属性
}
二.Category的加载处理过程
1.通过runtime加载某个类的所有Category的数据
2.把所有category的方法,属性,协议数据合并到一个大数组中(后面参与编译的category数据会在数组的前面)
3.将合并后的分类数据(方法,属性,协议),插入到类原来数据的前面
- 导致:
1.同样的方法有限调用分类的方法
2.最后面参与编译的分类方法,优先调用
三.Category 和 Class extension(匿名分类/类扩展)的区别
1.Class Extension在编译的时候,它的数据就已经包含在类信息中
2.Category是在运行时,才会将数据合并到类信息中
四. +load 和 +initialize(匿名分类/类扩展)的区别
+load方法
1.会在runtime加载类,分类的时候调用
2.每个类,分类的+load,在程序运行过程中只调用一次
3.调用顺序:
1>先调用类的load 先编译的类优先调用load,调用子类的load之前,会先调用父类的load
2>在调用分类的load 先编译的分类,优先调用
+initialize方法
- 会在类第一次接受到消息的时候调用
- 会先调用父类的+initialize的方法,再调用子类的方法(每个类只会初始化一次)
区别:
- 调用方式:
load是根据函数地址直接调用
initialize是通过objc_msgSend调用 - 调用时刻:
load是runtime加载类,分类的时候调用(只会调用一次)
initialize是类第一次接收到消息时候会调用,每一个类只会initialize一次(父类的initialize可能会被调用多次)如果分类实现了+initialize就覆盖类本身的initialize调用
五.分类可以添加成员变量吗?
(添加之后只是声明了set和get方法,但是没有写成属性也没有实现set和get方法)
默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。但可以通过关联对象来间接实现
关联对象提供了以下API
添加关联对象
void objc_setAssociatedObject(id object, const void * key,
id value, objc_AssociationPolicy policy)获得关联对象
id objc_getAssociatedObject(id object, const void * key)移除所有的关联对象
void objc_removeAssociatedObjects(id object)