+load:
1.+load方法什么时候调用?
程序启动时,由dyld通过load_images中的call_load_methods进行调用。
2.+load方法调用原理
找到类和分类中的+load方法的IMP,直接调用。
3.+load方法调用顺序?
1.按照编译的先后顺序,依次循环加载类的+load,父类的+load会先于子类被加载.
2.当类的+load加载完,开始加载分类的+load。
3.按照编译的先后顺序,依次循环加载分类的+load。
4.+load方法只走一次。
4.举例:
例如我们有父类Father、子类Son、分类Father (Test1)、Father (Test2)。
则加载的顺序依次为:
[Father + load]
[Son + load]
[Father (Test1) + load]
[Father (Test2) + load]
5.源码加载流程:
+ initialize
1.+initialize方法什么时候调用?
第一次收到消息的时候调用。
- +initialize方法调用原理?
1.第一次收到消息的时候,确保类和元类都实例化,且没有调用过+initialize方法。
2.通过objc_msgSend发送@selector(initialize)消息,进行调用。
3.+initialize方法调用顺序?
先调用父类的+initialize方法,再调用子类的+initialize方法
4.+initialize方法调用次数?
1次。
- +initialize源码调用流程:
1.我们在调用`objc_msgSend`方法后,消息转发来到`lookUpImpOrForward`
2.判断是不是第一次调用、类是否调用过`+initialize`,如果没有则会对类进行初始化。
3.由于`+initialize`是类方法,存在元类中.需要保证元类已经实例化`initializeNonMetaClass:`
4.我们看到首先确保父类已经执行过`+initialize`,之后调用当前类的`callInitialize:`方法
6.源码:
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.
// 确保父类的+initialize已经调用过了,否则先走父类
supercls = cls->superclass;
if (supercls && !supercls->isInitialized()) {
initializeNonMetaClass(supercls);
}
// Try to atomically set CLS_INITIALIZING.
SmallVector<_objc_willInitializeClassCallback, 1> localWillInitializeFuncs;
{
monitor_locker_t lock(classInitLock);
if (!cls->isInitialized() && !cls->isInitializing()) {
cls->setInitializing();
reallyInitialize = YES;
// Grab a copy of the will-initialize funcs with the lock held.
localWillInitializeFuncs.initFrom(willInitializeFuncs);
}
}
if (reallyInitialize) {
// We successfully set the CLS_INITIALIZING bit. Initialize the class.
// Record that we're initializing this class so we can message it.
_setThisThreadIsInitializingClass(cls);
if (MultithreadedForkChild) {
// LOL JK we don't really call +initialize methods after fork().
performForkChildInitialize(cls, supercls);
return;
}
for (auto callback : localWillInitializeFuncs)
callback.f(callback.context, cls);
// Send the +initialize message.
// Note that +initialize is sent to the superclass (again) if
// this class doesn't implement +initialize. 2157218
if (PrintInitializing) {
_objc_inform("INITIALIZE: thread %p: calling +[%s initialize]",
objc_thread_self(), cls->nameForLogging());
}
// Exceptions: A +initialize call that throws an exception
// is deemed to be a complete and successful +initialize.
//
// Only __OBJC2__ adds these handlers. !__OBJC2__ has a
// bootstrapping problem of this versus CF's call to
// objc_exception_set_functions().
#if __OBJC2__
@try
#endif
{
// 核心重点
callInitialize(cls);
if (PrintInitializing) {
_objc_inform("INITIALIZE: thread %p: finished +[%s initialize]",
objc_thread_self(), cls->nameForLogging());
}
}
#if __OBJC2__
@catch (...) {
if (PrintInitializing) {
_objc_inform("INITIALIZE: thread %p: +[%s initialize] "
"threw an exception",
objc_thread_self(), cls->nameForLogging());
}
@throw;
}
@finally
#endif
{
// Done initializing.
lockAndFinishInitializing(cls, supercls);
}
return;
}
else if (cls->isInitializing()) {
// We couldn't set INITIALIZING because INITIALIZING was already set.
// If this thread set it earlier, continue normally.
// If some other thread set it, block until initialize is done.
// It's ok if INITIALIZING changes to INITIALIZED while we're here,
// because we safely check for INITIALIZED inside the lock
// before blocking.
if (_thisThreadIsInitializingClass(cls)) {
return;
} else if (!MultithreadedForkChild) {
waitForInitializeToComplete(cls);
return;
} else {
// We're on the child side of fork(), facing a class that
// was initializing by some other thread when fork() was called.
_setThisThreadIsInitializingClass(cls);
performForkChildInitialize(cls, supercls);
}
}
else if (cls->isInitialized()) {
// Set CLS_INITIALIZING failed because someone else already
// initialized the class. Continue normally.
// NOTE this check must come AFTER the ISINITIALIZING case.
// Otherwise: Another thread is initializing this class. ISINITIALIZED
// is false. Skip this clause. Then the other thread finishes
// initialization and sets INITIALIZING=no and INITIALIZED=yes.
// Skip the ISINITIALIZING clause. Die horribly.
return;
}
else {
// We shouldn't be here.
_objc_fatal("thread-safe class init in objc runtime is buggy!");
}
}
void callInitialize(Class cls)
{
((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));
asm("");
}