问题一:Category
中有load方法吗?
答:有的,但是和其他方法不同,Category 中的load
和类中的load
方法,并不是简单的覆盖或者继承。用一个简单的工程可以看出:
LoadClass.m:
1 | #import "LoadClass.h" |
LoadClass+LoadClassCategory.m:
1 |
|
输出:
1 | 2019-11-10 20:57:22.986038+0800 LoadDemo[88431:1086125] Class Load Execute |
从输出可以看出,并没有出现方法覆盖的情况,两个load
方法都被执行了。
问题二:load方法是什么时候被调到的?
要探究这个问题其实很简单,只需要在上述代码中的load
方法中下一个断点,查看调用堆栈即可:
程序运行并命中断点之后,查看输出:
这里我们主要看load
的上层调用load_images
。显然这个时候,我们需要借助runtime源码
去分析。
首先找到这个函数:
1 |
|
函数内部其实很简单,就是几个函数的调用,这里,我们主要关注两个函数—–prepare_load_methods
、call_load_methods
。
先看prepare_load_methods
:
1 | void prepare_load_methods(const headerType *mhdr) |
看函数的内部流程和调用,其实不难看出,prepare_load_methods
函数内部遍历所有类,并调用schedule_class_load
函数,将所有类中的load
方法加入列表中,之后有遍历所有的category
并调用add_category_to_loadable_list
函数将category
中的load
方法加入列表中。大致的流程就是这样子的,如果想更深入的研究load
方法添加到列表中的细节,可以详细分析一下这两个函数。
接下来看看call_load_methods
是怎么调用load
方法的。
1 | /*********************************************************************** |
根据代码和注释,可以清楚的看出,load
方法的调用流程为:先调用类中的load
方法,再调用类别中的load
方法。这其实可以说明一个问题:类中的load
方法比类别中的load
方法先执行。
到这里,其实咱们就可以回答刚刚的那个问题了:
答:load
方法是在类或者类别添加到runtime
的时候,被调用的,而且其调用顺序是:先类中的load
,再类别中的load
。