OC中的Category(三)
OC中+initialize
函数加载和调用
OC对象是在查找方法时判断自己有没有初始化,如果没有就会调用初始化方法,在调用自己的初始化方法之前会调用父类的初始化方法。
调用initialize方法是通过runtime的objc_msgSend的方式调用,所以会存在如果子类没有实现会调用父类的initialize方法,并且优先调用类分类中存在的initializ方法
-
+initialize
方法会在类第一次接收到消息时调用 - 调用顺序:
先调用父类的+initialize,再调用子类的+initialize
(先初始化父类,再初始化子类,每个类只会初始化1次)
+initialize和+load的区别
- 调用方式
- load是根据函数地址直接调用
- initialize是通过objc_msgSend调用,如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次)如果分类实现了+initialize,就覆盖类本身的+initialize调用
- 调用时刻
- load是runtime加载类、分类的时候调用(只会调用1次)
- initialize是类第一次接收到消息的时候调用,每一个类只会initialize一次(父类的initialize方法可能会被调用多次)
load、initialize的调用顺序?
- load
先调用类的load,先编译的类,优先调用load,调用子类的load之前,会先调用父类的load
再调用分类的load,
先编译的分类,优先调用load
- initialize
- 先初始化父类
- 再初始化子类(可能最终调用的是父类的initialize方法)
源码分析
objc-run-timenew.mm文件,查找方法实现
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);
}
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;
}
IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
bool initialize, bool cache, bool resolver)
{
.
.
.
if (initialize && !cls->isInitialized()) {
runtimeLock.unlockRead();
_class_initialize (_class_getNonMetaClass(cls, inst));
runtimeLock.read();
}
.
.
.
}
void _class_initialize(Class cls)
{
assert(!cls->isMetaClass());
Class supercls;
bool reallyInitialize = NO;
supercls = cls->superclass;
if (supercls && !supercls->isInitialized()) {
_class_initialize(supercls);
}
callInitialize(cls);
}
void callInitialize(Class cls)
{
((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
asm("");
}