People talk a lot about load and initialize,

In fact, there is really no relationship between them, just because of the use of less, so it is contrasted

Load is called before main and in the order of parent class -> current class -> class

Initialize is called after main and only when the class sends its first message, so let’s explore

A lookUpImpOrForward imporforward method is used to find the imp. If the imp does not exist, look for it from cache or RW’s methods, and locate it directly to _class_initialize

_class_initialize Is called when initialize is not called, as shown below

if (initialize && ! cls->isInitialized()) { runtimeLock.unlock(); _class_initialize (_class_getNonMetaClass(cls, inst)); runtimeLock.lock(); // 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 }Copy the code

The _class_initialize method of the superclass is called recursively when the _class_initialize method of the superclass is not called. Finally, callInitialize when reallyInitialize is true, and then callInitialize

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; } } 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; } // 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]", pthread_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]", pthread_self(), cls->nameForLogging()); } } #if __OBJC2__ @catch (...) { if (PrintInitializing) { _objc_inform("INITIALIZE: thread %p: +[%s initialize] " "threw an exception", pthread_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!" ); }}Copy the code

The callInitialize method is implemented by calling objc_msgSend and sending the message directly

void callInitialize(Class cls)
{
    ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
    asm("");
}
Copy the code

Therefore, we conclude that initialize is called after main, the first time the method is called, in the order of the parent class -> current class, and only once

Classification and the current class call order, can be method lookup flow analysis, if you saw the previous article roughly, you can guess the result:

Classification of the parent class -> current class classification

Note: If the current class does not implement this method, then the parent class method will be called, so the parent class method may be called multiple times. If the classification method does not exist, the method of the current class is called; If the class method exists, only the class is called, not the same method of the current class

(Class is at the top of the method list. The system will find class calls first when calling methods.)