load类方法探秘

在平时的开发过程中可能我们很少会用到load类方法,但是面试的时候一般会问到load类方法,所以就对它做一个全面的剖析。

+load类方法会在Runtime加载类、分类的时候调用。也就是说,不管+load类方法的所在类有没有真正在代码中用到,只要程序运行起来了,就会把所有的类都加载进程序的内存中,即都会调用他们的+load类方法。

每个类、分类的+load类方法在程序运行的过程中只会被调用一次。

一般情况下开发者不会主动去调用+load类方法,都是让系统自动进行调用。

由于在Demo中创建的类比较多,而且各个类之间的关系也比较复杂,就不在这里一一列举Demo中的代码内容了,请各位移步本人的Github,请根据Demo里面的内容继续看下面的文章:

Github Demo

+load类方法的调用原理:

  1. 调用顺序:对于一个原类有多个分类的情况,在程序运行以后,系统会先调用原类中的+load类方法,然后再逐个调用分类中的+load类方法;
  2. 调用原理:根据分类的实现原理,在程序编译之后,分类的底层结构是struct category_t结构体,这个结构体里面存储着分类的对象方法、类方法、属性和协议信息。在程序运行的时候,Runtime会动态地将分类里面的数据合并到类信息(class对象、meta-class对象)中。在本Demo中,程序运行以后,系统会把ZPPerson类的分类ZPPerson+ZPTest和ZPPerson+ZPTest1类中的"load"和"test"类方法合并到ZPPerson类的meta-class对象中去,这样算上它自己的类方法就一共有三组"load"和"test"类方法了,这些类方法都存储在ZPPerson类的meta-class对象中的类方法数组中,根据《day05》中的《Category》Demo中所讲的原类和分类中的实例方法或者类方法的调用原则,排在前两组的应该是两个分类的类方法,最后一组应该是本类的类方法。按理来说当系统调用"load"类方法的时候,调用的应该是第一组中的"load"类方法,即最后参与编译的分类(ZPPerson+ZPTest1)中的"load"类方法,但实际上系统把每个类中的"load"类方法都调用了一遍,其原因就在于,从Runtime源码中可以看到系统会先调用原类的"load"类方法,然后再调用分类的"load"类方法。在调用原类的"load"类方法的时候,系统先获取到这个类方法的指针,然后根据这个指针再去调用原类的"load"类方法。在调用分类的"load"类方法的时候,跟调用原类的相似,也是先获取到这个类方法的指针,然后根据这个指针再去调用这个分类的load"类方法;
  3. 对于一个原类有多个分类的情况,调用+load类方法和调用其他实例方法和类方法([ZPPerson test];)的区别:
    前者是通过指针的方式直接调用"load"类方法的,后者是通过Runtime消息发送的方式进行调用的。

+load类方法调用顺序的原则:

  1. 对于没有任何关系的类(ZPPerson、ZPDog、ZPCat)来讲,系统会先调用先编译的类的load类方法,后调用后编译的类的load类方法;
  2. 对于有父子关系的两个类(ZPPerson、ZPStudent)来讲,系统会先调用父类的load类方法,然后再调用子类的load类方法;
  3. 对于有分类关系的两个类(ZPPerson、ZPPerson+ZPTest)而言,系统先调用原类的load类方法,再调用分类的load类方法;
  4. 对于多个分类(ZPPerson+ZPTest、ZPPerson+ZPTest1、ZPStudent+ZPTest、ZPStudent+ZPTest1)而言,不管他们的原类是什么关系,系统都会按照编译的先后顺序调用它们的load类方法,即先调用先编译的分类的load类方法,后调用后编译的分类的load类方法。

也可以把上述的原则概括如下:

  1. 先调用原类的load类方法:
  • 按照编译的先后顺序进行调用(先编译,先调用);
  • 在调用子类的load类方法之前,会先调用父类的load类方法。
  1. 再调用分类的load类方法:
    按照编译的先后顺序进行调用(先编译,先调用)。

文件的编译顺序可以在下图所示处进行查看:

load类方法探秘_第1张图片
image.png

”三人行,必有我师焉“, 欢迎各位批评指正。
如果您还觉得我写的不错的话请您点赞加关注,您的肯定是我前进的最大动力!
我是爱学习也爱您的树懒O(∩_∩)O

你可能感兴趣的:(load类方法探秘)