7. Category的实现原理
- Category编译之后的底层结构是struct Category_t,里面存储着分类的属性,实例方法,类方法,协议信息
- 在程序运行的时候,runtime会将Category的数据,合并到类信息中,注意,在合并的过程中,分类的方法会被方法列表的数组前面位置,最后编译的分类,放在方法列表数组的第一位,这将会导致同样的方法,如果在分类和类中都实现,分类方法的优先级高
Category的底层实现
8.Category和Extension的区别是什么?
- Extension 在程序编译的时候,它的数据就已经包含在类信息中了
- Category 在程序运行的时候,通过runtime将分类中数据合并到类信息中去
9.Category中load方法什么时间调用?
- load方法会在runtime加载分类的时候调用;
- 每个分类的load方法,在程序运行过程中只会调用一次
- load方法是通过函数指针直接调用的,不走
objc_msgSend()
方法
调用顺序
- 先调用类的load方法
1. 按照编译的顺序进行调用(先编译,先调用)
2. 在调用子类的load方法之前,一定先调用父类的load方法- 在调用分类的load方法
1. 按照编译的顺序进行调用(先编译,先调用)
如果我们主动调用load方法,需要注意
分析:
- load方法只会被调用一次,而且调用时间是在runtime加载类的时候就被调用.
- 而当我们主动调用子类的load方法,这时候其实是走
objc_msgSend()
,先通过isa指针
去找方法列表,如果isa没有找到,就会再通过superclass指针
去找父类方法列表,这时候父类方法列表中有分类的方法和它本身的方法,首先加载分类的方法.
10. initialize方法和load方法的不同
- 调用机制不同
- load是根据函数指针地址直接调用
- initialize是通过
objc_msgSend()
方法调用
2.调用时刻不同
- load是runtime加载类,分类的时候调用(只会调用一次)
- initialize是类第一次收到消息的时候进行调用,一个类的initialize方法只会调用一次(父类的可能会被调用多次)
- 调用顺序不同
load
- 先调用类的load方法
a. 先编译的类先调用
b. 调用子类的load方法之前,会先调用父类的load方法 - 在调用分类的load方法
a. 先编译的类,先调用load方法
initialize
- 先初始化父类的initialize方法
- 在初始化子类的initialize方法 (如果子类没有实现initialize方法,会调用父类的initialize方法)