Category的底层分析之load

31 篇文章 0 订阅

今天我们就围绕一个面试题来从源码的角度分析答案!

一、Category中有load方法吗?load方法是什么时候调用的?load方法能继承吗?如果分类又存在继承是如何加载load顺序的呢?

首先我们先看下下面的代码,我们先看代码运行结果,再从源码上分析!

GDPerson.m文件里面+(void)load{ NSLog(@"GDPerson+load"); } GDPerson+Test1.m文件里面+(void)load{ NSLog(@"GDPerson+Test1+load");}GDPerson+Test2.m文件里面+(void)load{ NSLog(@"GDPerson+Test2+load");}

1.GDPerson+Test1和GDPerson+Test2是GDPerson分类;

2.GDStudent+Test1和GDStudent+Test2是GDStudent分类;

3.GDStudent继承于GDPerson

从上面的结果我们可以看出,分类是在加载分类的时候调用load方法,没有任何操作,是主动调用。

二、GDPerson和GDPerson+Test1和GDStudent+Test2调用顺序和编译顺序有关吗?

请看下面的截图:

我们无论怎么调整编译顺序,GDPerson的load方法总是先输出,剩下2个分类是按照分类的顺序加载load方法。

然后我们在GDPerson和它的分类里面都加一个+(void)test方法,按照上面的顺序,我们知道肯定优先执行GDStudent+Test2的test,我想具体原因就不说了,我之前的博客都有好好介绍这些问题

思考

从之前我们知识体,我们知道类方法都是存在元类对象中的,我们也知道+(void)test肯定也是存在元类对象中的,那么GDPerson类和分类的三个+(void)test肯定是在元类对象,那么+(load)是什么样的呢?这里我们可以看一下元类对象里面到底存了哪些方法,还记得我之前的一篇博客吗?有一个方法可以获取对象中的方法(探索KVO的本质(二)),可以这里面查看。

我再贴一遍方法:

从这里可以看出,load方法是合并在元类对象里面的,这也跟我们之前的博客说的知道点是吻合的

窥探源码来论证我们上面说的结论

源码地址,我之前几个博客都有说,这里就不说了,直接打开objc4最新源码查看:

我先把查看源码顺序贴上,再和大家一起看一下。

 

objc-os.mm就是程序的入口,_objc_init初始化;load_image,image是代表镜像,load_image正好是我们要的load的方法,接下来我就一步一步的带着看一下

这里很清楚的解决了我们的疑问,类的load方法先调用,分类的load方法后调用。继续看call_class_loads具体是怎么调用的

这里我们清楚了,这个不像我们之前说的,是通过直接找的内存地址直接调用,而不是我们之前的先通过isa找到类对象,再通过类对象的isa找到元类...等等,所以是运行时就会直接调用load方法。

接下来分类的方法也是同样的道理,大家可以自己看一下,这里就不说了。相信大家心中都有答案。

接下来我们看一个更复杂的情况

如果出现继承会是怎么样的呢?

下面我把GDStudent是继承GDPerson,然后GDStudent+test1和GDStudent+test2是GDStudent分类

无论怎么修改编译顺序,父类的load方法都是优先调用,再调用本类,再根据编译顺序,调用其他分类,这个大家可以自己去验证验证,接下来我们用源码分析看看到底是不是这样。

出现继承的源码分析调用顺序

先看类再看分类,我们还是先看call_class_loads方法的实现

所以接下来我们就去研究classes的顺序,在调用之前有个prepare_load_methods方法,那很有可能就是在这里面准备了classes的顺序,我们进去看一下有个schedule_class_load,schedule是规划的意思,就是规划我们的类加载,那就接着看(过程比较多,也比较简单,我标记的比较清楚,很容易尝试),请看下面的图

从上面的图可以看出数组的顺序是父类在前面,而且是schedule_class_load是递归调用会调用所有父类,所以是优先加载。也是优先调用,把我们在看一下add_class_to_loadable_list(cls)的具体实现吧

说了这么多,我们终于可以总结了😄

总结:

+load方法会在runtime加载类、分类时调用

每个类、分类只会在程序运行过程中调用一次

调用顺序:

1.首先会调用类的load方法;

2.调用子类的load方法之前会优先调用父类的load方法;

3.按照编译的顺序(先编译,先调用)

4.再调用分类的load方法,按照先编译,先调用

接下来我们解答面试题

load方法的继承比较简单,我就不说了,它也是消息机制发送,通过isa,所以它会优先调用分类的load,这个大家自己尝试!

一、Category中有load方法吗?load方法是什么时候调用的?load方法能继承吗?

有load方法(这个问法就很奇怪)

load方法是在runtime加载类、分类的时候调用

load方法可以继承,但是一般情况下不会主动调用load方法,都是让系统自动调用

接下来博客我会介绍iOS类别(Category关于initialize的底层知识)的其他底层知识.

如果觉得我写得对您有所帮助,请关注我,我会持续更新😄

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值