想搞明白initialize就需要从id objc_msgSend(id self, SEL _cmd, ...);
入手,但是此函数使用汇编实现,很多东西看不明白,但是根据里边的注释可以看到调用方法拿到IMP会使用IMP objc_msgLookup(id self, SEL _cmd, ...);
。然后最终可以确定其实最终调用的是这个函数Method class_getInstanceMethod(Class cls, SEL sel)
。下面根据这个函数开始分析。
一. 调用顺序
1. Method class_getInstanceMethod(Class cls, SEL sel)
Method class_getInstanceMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
// This deliberately avoids +initialize because it historically did so.
// This implementation is a bit weird because it's the only place that
// wants a Method instead of an IMP.
#warning fixme build and search caches
// Search method lists, try method resolver, etc.
lookUpImpOrNil(cls, sel, nil,
NO/*initialize*/, NO/*cache*/, YES/*resolver*/);
#warning fixme build and search caches
return _class_getMethod(cls, sel);
}
2. 调用 IMP lookUpImpOrNil(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver)
IMP lookUpImpOrNil(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver)
{
IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
if (imp == _objc_msgForward_impcache) return nil;
else return imp;
}
3. 调用 IMP lookUpImpOrForward(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver)
IMP lookUpImpOrForward(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver)
{
IMP imp = nil;
bool triedResolver = NO;
......
if (initialize && !cls->isInitialized()) {
runtimeLock.unlockRead();
_class_initialize (_class_getNonMetaClass(cls, inst));
runtimeLock.read();
// If sel == initialize, _class_initialize will send +initialize and
// then the messenger will send +initialize again after this
// procedure finishes. Of course, if this is not being called
// from the messenger then it won't happen. 2778172
}
......
return imp;
}
4. 调用 void _class_initialize(Class cls)
这里是个递归,在调用一个类的initialize
之前先检查是否有父类,如果有父类并且父类没有被初始化过,则先调用父类的initialize
。
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);
}
......
{
callInitialize(cls);
if (PrintInitializing) {
_objc_inform("INITIALIZE: thread %p: finished +[%s initialize]",
pthread_self(), cls->nameForLogging());
}
}
......
}
5. 调用 void callInitialize(Class cls)
void callInitialize(Class cls)
{
((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
asm("");
}
二. 如果调用者不是元类对象
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta()
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
如果不是元类对象就返回该对象的isa,确保返回元类对象。
总结调用顺序:
class_getInstanceMethod -> lookUpImpOrNil -> lookUpImpOrForward -> _class_initialize -> callInitialize
网友评论