Category的实现原理。
-
Category
编译之后的底层结构是struct category_t
,里面存储着分类的实例方法
、类方法
、属性
、协议信息
- 在程序运行的时候,
Runtime
会将Category
的数据,合并附加到类信息中(class
对象、meta-class
对象) - PS1:
Runtime
将分类的方法放在原来的方法的前面,因此分类的方法优先级更高,所以如果有重名的方法,会优先调用分类的方法 - PS2:如果多个分类有重名的方法,【后】编译的分类的方法优先级更高,因为Runtime里面的方法列表附加操作的顺序是下标从大到小进行的,越往后越靠前
- PS3:在
Tatgets
->Build Phases
->Compile Sources
中可以控制编译顺序,编译是从上到下的顺序,想调用的优先级高的就往下放
Category和Class Extension的区别是什么?
-
Class Extension
在编译的时候,它的数据就已经包含在类信息中 -
Category
是在运行时,才会将数据合并到类信息中
Category中有load方法吗?load方法是什么时候调用的?load方法能继承吗?
- 有。
-
load
方法在Runtime
加载类、分类的时候调用 -
load
方法可以继承,在子类没有重写load
方法,主动去调用load
方法(消息发送机制)时会调用父类的load
方法,说明是有继承关系的,但是一般情况下不会主动去调动load
方法,都是让系统自动调用(在Runtime
加载时是直接拿到load
方法的地址去调用,之后手动调用时其实就是利用消息发送机制:子类没有load
方法就会去父类的方法列表里面找)
load、initialize方法的区别是什么?它们在Category中的调用的顺序?以及出现继承时它们之间的调用过程?
- 区别:
- 调用方式
load
是根据函数地址直接调用
initialize
是通过objc_msgSend
调用
- 调用时刻
load
是Runtime
加载(所有参与编译的)类、分类的时候调用,只会调用1次
initialize
是类第一次接收到消息的时候调用,每一个类只会调用initialize
一次,但父类的initialize
方法可能会被调用多次(例如:子类和子类的分类都没有实现initialize
方法时就会去调用父类的initialize
方法)
- 调用顺序
load
:
先调用类的load
先编译的类,优先调用load
调用子类的load
之前,会先调用父类的load
再调用分类的load
先编译的分类,优先调用load
initialize
:
调用父类的initialize
(初始化)
再调用子类的initialize
(初始化)
可能最终调用的是父类的
initialize
(子类没有实现initialize
)
Category能否添加成员变量?如果可以,如何给Category添加成员变量?
- 不能直接给
Category
添加成员变量,但是可以间接实现Category
有成员变量的效果关联对象
。