load

This method is called when the Runtime loads classes and classes, and you can use custom implementations to do some of the class customization. Typically used to execute code that will only be executed once.

The order in which load is called can be seen from the official documentation:

  • Call the parent’s +load first, then the child’s.
  • Call the class’s +load first, then the class’s.
  • If it is not an inherited class, compile first, call first; Peer classification is also compile first call first.

Let’s verify the above call relationship with the source code. Source code version is objC4-818.2.

Because +load is called when the Runtime loads classes and classes, the source entry remains the _objc_init method. The load_images method is called in this method.

  • load_images
void load_images(const char *path __unused, const struct mach_header *mh) { ...... // Discover load methods {mutex_locker_t lock2(runtimeLock); prepare_load_methods((const headerType *)mh); } // Call methods (without runtimelock-re-entrant) call_load_methods(); }Copy the code
  • Prepare_load_methods: Load methods that find all classes and categories.
void prepare_load_methods(const headerType *mhdr) { ...... // Find the class load method for (I = 0; i < count; i++) { schedule_class_load(remapClass(classlist[i])); } / / find category_t load method for classification of * const * categorylist = _getObjc2NonlazyCategoryList (MHDR, & count); for (i = 0; i < count; i++) { ...... add_category_to_loadable_list(cat); }}Copy the code
  • Schedule_class_load: Finds the load method of all classes.
static void schedule_class_load(Class cls) { ...... // Ensure superclass-first ordering. Ensure that the superclass is loaded first, then the subclass is loaded. schedule_class_load(cls->getSuperclass()); add_class_to_loadable_list(cls); . }Copy the code
  • call_load_methods
void call_load_methods(void) { ...... // This do-while loop verifies that the load method of the class is called first and then the load method of the class is called. Do {// 1. Repeatedly call class +loads until there aren't any more while (loadable_classes_used > 0) {// invoke the load of class call_class_loads(); } // 2. Load more_categories = call_category_loads(); // 3. Run more +loads if there are classes OR more untried categories } while (loadable_classes_used > 0 || more_categories); . }Copy the code
  • Call_class_loads: calls the load method of the class.
static void call_class_loads(void) { ...... // call directly from method address (*load_method)(CLS, @selector(load)); . }Copy the code
  • Call_category_loads: Calls the load method of the classification.
static bool call_category_loads(void) { ...... // call directly from method address (*load_method)(CLS, @selector(load)); . }Copy the code

(*load_method)(cls, @selector(load)); We can also conclude from this code that the +load method is called directly from the method address, rather than following the same process as the message mechanism.

Runtime +load call flow chart:

initialize

The following conclusions can be drawn from the official documents:

  • It is called the first time a class receives a message and only once per class.
  • It is thread-safe.
  • If the subclass does not implement the method, the parent class may be called multiple times; If the class implements the method, only the method implementation of the class is called.
+ (void)initialize {if (self == [ClassName self]) {//... do the initialization ... }}Copy the code

Then, or through the source code to verify the above conclusion.

  • class_initialize
Class class_initialize(Class cls, id obj)
{
    runtimeLock.lock();
    return initializeAndMaybeRelock(cls, obj, runtimeLock, false);
}
Copy the code
  • initializeAndMaybeRelock
static Class initializeAndMaybeRelock(Class cls, id inst,
                                      mutex_t& lock, bool leaveLocked)
{
    ......
    // runtimeLock is now unlocked, for +initialize dispatch
    ASSERT(nonmeta->isRealized());
    initializeNonMetaClass(nonmeta);

    if (leaveLocked) runtimeLock.lock();
    return cls;
}
Copy the code
  • initializeNonMetaClass
void initializeNonMetaClass(Class cls) { ...... // Make sure super is done initializing BEFORE beginning to initialize cls. +initialize calls supercls = CLS ->getSuperclass(); if (supercls && ! supercls->isInitialized()) { initializeNonMetaClass(supercls); }... callInitialize(cls); . }Copy the code
  • callInitialize
Void callInitialize(Class CLS) {// objc_msgSend; ((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize)); asm(""); }Copy the code

+initialize call flowchart:

conclusion

  • Call timing: + Load is called when the Runtime loads classes and classes; +initialize is called the first time the class receives a message;
  • Call nature: +load is called directly from the method address; +initialize is called via the message mechanism.
  • Call order:
    • Load calls the class first, then the class. If a class has a parent class, the parent class is called first and then the child class is called.
    • +load flat class compile first call; The same is true of horizontal classification.
    • Initialize calls the parent class first and then the subclass. If the classification is also achievedWill onlyCall classification.
    • If a subclass does not implement + Initialize, the parent class may be called multiple times.