底层5:Category、+load、+initialize
面试题:Category
1.Category的使用场合时什么?
2.Category的实现原理。
Category编译后的底层结构是struct Category_t,里面存储分类的对象方法、类方法、属性、协议信息。在程序运行的时候,runtime会将Category的数据,合并到类信息中(类对象、元类对象中)
3.Category的Class Extension的区别是什么?
Class Extension在编译的时候,它的数据就已经包含在类信息中。Category是在运行时,才会将数据合并到类信息中。
4.Category中有load方法吗?load方法什么时候调用的?load方法能继承吗?
有+load方法;
load方法在runtime加载类、分类的时候调用;
load方法严格来说可以继承,但是一般情况下不回去主动调用,都是让系统自动去调用。
5.load、initialize方法的区别是什么?他们在category中的调用顺序?以及出现继承时他们之间的调用过程?
区别:
调用方式:
1)load是根据函数地址直接调用;
2)initialize是通过objc_msgSend调用。
调用时刻:
1)load是runtime加载类、分类的时候调用(只会调用一次);
2)initialize是类第一次接收到消息的时候调用,每一个类只会initialize一次(父类的initialize方法可能会被调用多次)。
调用顺序:
1.load调用顺序:
1>先调用类的load。
a)先编译的类,优先调用load;
b)调用子类的load之前,会先调用父类的load。
2>再调用分类的load。
a)先编译的分类,优先调用load。
2.initialize调用顺序:
1> 先初始化父类
2> 再初始化子类(可能最终调用的是父类的+initialize)
继承调用顺序:
调用子类的load之前,会先调用父类的load。
先调用父类的initialize,再调用子类的initialize(如果子类没有initialize,会调用父类的initialize)。
Category的原理:
通过Runtime加载某个类的所有Category数据。
把所有Category的方法、属性、协议数据,合并到一个大的数组中,后面参与编译的Category数据,会在数据的前面。
将合并后的分类数据(方法、属性、协议)插入到类原来数据的前面。
Category的底层结构
+load方法
+load方法会在runtime加载类、分类时调用。
每个类、分类的+load方法在程序运行过程中只调用一次
调用顺序:
1.先调用类的+load方法。
按照编译先后顺序调用(先编译,先调用);
调用子类的+load方法之前会先调用父类的+load方法。
2.再调用分类的+load方法。
按照编译先后顺序(先编译,先调用)。
+initialize方法:会在类第一次接收到消息的时候调用。
是通过消息机制来调用的。
调用顺序:
先调用父类的+initialize,再调用子类的+initialize(可能不会调用)。
(先初始化父类,在初始化子类,每个类只初始化一次。)
+initialize和+load最大的区别是:
+initialize是通过objc_msgSend进行调用的,所以有以下特点:
1)如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次);
2)如果分类实现了+initialize,就会覆盖本身的+initialize调用。