- +initialize方法在类第一次接收到消息的时候被调用
-
调用顺序
1.先调用父类的,再调用子类的
2.如果子类没实现+initialize方法,会调用父类的+initialize。所以父类的+initialize可能被调用多次
3.如果分类实现了+initialize,会覆盖类本身的+initialize
源码分析
源码版本objc4-781.tar.gz
首先查找函数调用顺序,在类中重写+initialize,添加断点。得到函数的调用栈。
所以源码解读顺序为
objc-runtime-new.mm
IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
static Class initializeAndLeaveLocked(Class cls, id obj, mutex_t& lock)
static Class initializeAndMaybeRelock(Class cls, id inst,
void initializeNonMetaClass(Class cls)
void callInitialize(Class cls)
这里主要关注最后两个方法
/***********************************************************************
* class_initialize. Send the '+initialize' message on demand to any
* uninitialized class. Force initialization of superclasses first.
**********************************************************************/
void initializeNonMetaClass(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()) {
// 递归调用,父类的initialize在子类之前调用
initializeNonMetaClass(supercls);
}
...省略部分代码...
{
// 调用initialize方法
callInitialize(cls);
if (PrintInitializing) {
_objc_inform("INITIALIZE: thread %p: finished +[%s initialize]",
objc_thread_self(), cls->nameForLogging());
}
}
...省略部分代码...
}
在void initializeNonMetaClass(Class cls)
中可以看到首先会去判断父类是否初始化过了,如果没有调用父类的+ initialize方法,保证父类的+ initialize在子类之前调用。
接下来是callInitialize
方法
void callInitialize(Class cls)
{
((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));
asm("");
}
可以看到callInitialize
中直接通过objc_msgSend
方法调用+initialize方法。这也就解释了为什么+initialize子类没实现,会去调用父类中的。category中的会覆盖类本身的。
网友评论