在上一篇文章中(手把手带你探索load底层原理)探索了load的调用机制,本文是探索一下initialize的调用机制,并比较一下异同点。 +initialize
其实在平时开发中用的较少,通常用来初始化常量,不过面试中常会问到它与+load
的区别。面试
+initialize
方法是在类或它的子类收到第一条消息以前被调用的,这里所指的消息包括实例方法和类方法的调用。也就是说 +initialize
方法是以懒加载的方式被调用的,若是程序一直没有给某个类或它的子类发送消息,那么这个类的 +initialize
方法是永远不会被调用的。+initialize
或者子类在+initialize
中显式的调用了[super initialize]
,那么父类的+initialize
方法会被调用屡次。+initialize
,会只执行分类的+initialize
+initialize
方法在全部父类的+initialize
方法调用以后调用此次是在objc
源码中直接调试代码,在我提供的源码里新建一个target
, 以下图 函数
接下来建立Person
类,实现load
和initialize
方法,编译运行咱们刚才建立的target
post
运行结果只执行了load
方法,并无执行initialize
方法,因此可以获得结论:load
在文件被加载时就执行了,initialize
不主动调用atom
对于本文开头的几个结论,能够在这里都简单用代码验证一遍,我这里就再也不去一一验证了,直接开始探索源码。spa
我在load
里打印了一下self
,发现initialize
被调用了,那么看看断点处的initialize
3d
发现这里其实就进入到了runtime的消息查找流程,这里直接来到第三步,这里判断是否类已经初始化,没有初始化就作初始化操做。因此在这里能够验证开头的结论一,它是收到类的第一条消息后才调用的。 调试
看看_class_initialize
函数code
void _class_initialize(Class cls)
{
assert(!cls->isMetaClass());
Class supercls;
bool reallyInitialize = NO;
// Make sure super is done initializing BEFORE beginning to initialize cls.
// See note about deadlock above.
supercls = cls->superclass;
if (supercls && !supercls->isInitialized()) {
_class_initialize(supercls);
}
// Try to atomically set CLS_INITIALIZING.
{
monitor_locker_t lock(classInitLock);
if (!cls->isInitialized() && !cls->isInitializing()) {
cls->setInitializing();
reallyInitialize = YES;
}
}
//其他代码省略
callInitialize(cls);
复制代码
这里有一个标识符reallyInitialize
,在cls->setInitializing()
(给类的isa设置RW_INITIALIZING
标识),设置完后改成true
cdn
这里有拿到 supercls
,而后判断是否存在和是否初始化完成,未初始化则调用本身自己这个函数_class_initialize
,其实就是一个递归,用来确保全部父类的initialize
已经执行完,再执行当前类,这里和以前探索load
的时候的递归调用父类load
的方法原理相同。因此在这里能够验证开头的结论四:类的+initialize
方法在全部父类的+initialize
方法调用以后调用。blog
void callInitialize(Class cls) {
((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
asm("");
}
复制代码
callInitialize
, 使用了发送消息 objc_msgSend
的方式对 +initialize
方法进行调用。也就是说 +initialize
方法的调用与普通方法的调用是同样的,走的都是发送消息的流程。换言之,若是子类没有实现 +initialize
方法,那么继承自父类的实现会被调用;因此有告终论三:若是一个类的分类实现了 +initialize
方法,那么就会对这个类中的实现形成覆盖。