After the OC file is compiled, the class-related data structures remain in the object file and are parsed and used at run time. When the application is running, the information of the class is loaded and initialized. This process involves the two class methods of the class: Load and Initialize. Let’s take a look at the differences between the two methods. (First of all, these two methods are system calls, developers generally do not actively call the two methods, there is no point in doing so, so the rest of the explanation is for system calls, not active calls).

1. The load method

1.1 Call Timing

When we start the program, to participate in the compilation of class, the classification will be loaded into memory, the load method is invoked when the class is loaded (if the class has to realize the load method), this process has nothing to do with this class is used, that is to say, if you have a class (MyClass) even in the whole program is not used, There isn’t even a file to import the MyClass header, so the MyClass load method is called as well. The program’s main function is called after all classes and classes are loaded into memory, so the load method of all classes is called before the main function. And the load method for each class and category is called only once.

1.2 Call Sequence

If all classes and classes in a program implement load methods, all load methods will be called. Their execution order follows the following rules:

  • Execute all classes firstloadMethod, and then execute all classifiedloadMethods.
  • The implementation of the classloadMethod, the first compiled class is executed in the order in which it was compiled, but if a class inherits from another class, the parent class is executed firstloadMethod before executing its ownloadMethods.
  • Performing classificationloadMethod is compiled in the order in which categories are involved, with the first compiled category being executed first.

Build Phases –> Compile Sources (the top one is the first one to Compile, and we can drag the file to change the Compile order).

Here’s an example of the order in which the load methods are executed. The Person class has two classes: AAA and BBB. The men class has two classes: CCC and DDD. The Book class has nothing to do with the previous classes.

Explanation:

  • The compilation order is from top to bottom, with the top compiled first and the bottom compiled later. Since the class is executed firstloadAnd then perform the classificationload, the first class to participate in compilation ismenAnd themenInherited fromPerson, so execute firstPersontheload(thoughPersonIs post-compiled, but it is the parent class, so it is executed first), and then executedmentheload. The next thing that’s involved in compiling isBookClass, so execution followsBooktheload. The next class involved in compiling isPersonBecause of itsloadThe method has already been executed and will not be executed.
  • All of the classesloadMethods are executed after the start of the classificationload, the order in which categories participate in compilation ismen+ccc–>Person+aaa–>men+ddd–>Person+bbbSo it’s classifiedloadMethods are also executed in this order.

1.3 Execution Mode

We know that when a class has a method with the same name as the class, calling that method ends up executing the method in the class. The Person class and each of its classes have a load method called, but the Person class and each of its classes have load methods called.

This is because the load method is not called in the same way as a normal method. A normal method call is implemented through the message sending mechanism. It will first look up the method list of the class or metaclass. If it finds a method, it will execute.

When a load method is called, each class is directly called based on the address of the load method, rather than the objc_msgSend method lookup process. This means that a class implements a load method and does not execute it if it does not (and does not look up the parent class if it does not).

For a more detailed overview of the underlying implementation process, check out objC4’s source code. Here is the related function call process for reading the source code: Start with the _objc_init function in objC-os. mm –>load_images–>prepare_load_methods–>schedule_class_load–>add_class_to_loadable_list — ->add_category_to_loadable_list–>call_load_methods–>call_class_loads–>call_category_loads–>(*load_method)(cls, SEL_load).

1.4 What should I pay attention to when implementing the Load method

We usually do Method Swizzle in the Load Method, but otherwise, we try not to write code in the Load Method unless we really have to, especially not to use other classes in the Load Method, because at this point the other classes may not have been loaded into memory, and using them arbitrarily can be problematic.

If you do write some code in the load method, try to keep it as simple as possible and don’t do time-consuming or lockwaiting operations because the entire program blocks while executing the Load method, which can take too long to start or even fail to start.

2. The initialize method

2.1 Call Timing

The Initialize method is called when the class or one of its subclasses receives the first message. In this case, the message is the instance method or class method call, so all initialize calls are made after main. And the Initialize method is only called once by a class. Unlike the load method, the Initialize method will not be called if a class has not been used during the program’s execution.

2.2 Invocation Mode

The initialize method calls follow the same objc_msgSend process as normal method calls. So if a class and its classes implement the Initialize method, it will end up calling the methods in the class.

If the initialize method is implemented by both the subclass and its parent class, the parent class will be called first, and then the subclass will be called. By looking at the source code, we know that it is the initialize method of the parent class that is actively called during the underlying implementation.

Here’s an example:

PersonSub1 and PersonSub2 also implement Initialize. PersonSub3 and PersonSub4 do not implement initialize. Instantiate objects in the following order:

PersonSub1 *ps1 = [[PersonSub1 alloc] init]; Person *person = [[Person alloc] init]; PersonSub2 *ps2 = [[PersonSub2 alloc] init]; PersonSub3 *ps3 = [[PersonSub3 alloc] init]; PersonSub4 *ps4 = [[PersonSub4 alloc] init]; / / * * * * * * * * * * * * * * * printing result * * * * * * * * * * * * * * * 2020-01-06 15:52:38. 429218 + 0800 CommandLine [68706-7207027] + [Person the initialize] 2020-01-06 15:52:38.429250+0800 CommandLine[68706:7207027] +[PersonSub1 initialize] 2020-01-06 15:52:38.429287+0800 CommandLine[68706:7207027] +[PersonSub2 initialize] 2020-01-06 15:52:38.429347+0800 CommandLine[68706:7207027] +[Person Initialize] 2020-01-06 15:52:38.429380+0800 CommandLine[68706:7207027] +[Person initialize]Copy the code

The initialize method is called three times. The initialize method is called three times.

Here we need to explain the execution process of the underlying source code. Each class has a mark to record whether the class has called Initialize. I use a BOOL isInitialized to represent it, and then use selfClass to represent my own class and superClass to represent the parent class. Here I use pseudocode to describe the underlying source code execution process:

// Execute the code inside initialize if you have not already called itif(! selfClass.isInitialized){if(! Superclass.isinitialized){// Send a message to the parent class if initialize has not been performed. objc_msgSend(superClass,@selector(initialize)); SelfClass,@selector(initialize);} // initialize a message to your own class. If initialize succeeds, set isInitialized to YES. }Copy the code

Let me explain the results of the above operation according to this process:

  • First of all,PersonSub1Being used, while at this timePersonSub1theisInitializedIs NO and superclassPersontheisInitializedIs also NO, so a message is sent to the parent class firstinitializeAfter the execution is completePersontheisInitializedA YES. thenPersonSub1Execute one’s owninitializeAfter the execution is completePersonSub1theisInitializedA YES. So this is the first step to print+[Person initialize]And then print+[PersonSub1 initialize].
  • And then thePersonInstantiate, at this pointPersontheisInitializedIs YES, so it will not be called againinitialize. So I didn’t print anything at this step.
  • Then there isPersonSub2Instantiate, at this pointPersonSub2theisInitializedIs NO, the parent classPersontheisInitializedIs YES, so onlyPersonSub2Will performinitializeAfter the execution is completePersonSub2theisInitializedA YES. So what this step prints is+[PersonSub2 initialize].
  • thenPersonSub3Instantiate, at this pointPersonSub3theisInitializedIs NO, the parent classPersontheisInitializedIs YES, so onlyPersonSub3Will performinitializeBut because ofPersonSub3Do not implementinitialize, it goes to the parent class to find the implementation of the method, and when it finds it, it executes the parent classPersontheinitialize(Notice here isPersonSub3performPersonIn theinitializeRather thanPersonExecuted), after executionPersonSub3theisInitializedA YES. So what this step prints is+[Person initialize]. (Note that method information is printed here, indicating that it is executedPersonIn theinitialize“Instead of saying yesPersonOf the callinitialize).
  • Finally,PersonSub4Instantiate, this step is the same as the previous step, after executionPersonSub4theisInitializedA YES. This step is printing+[Person initialize].

The result is that Person, PersonSub1, PersonSub2, PersonSub3, and PersonSub4 have all been initialize once. The next two calls are for PersonSub3 and PersonSub4.

2.3 Precautions for Use

Although it is safer to use initialize than load (since all classes have already been loaded into memory by the time initialize is called), we should use initialize as little as possible. We should be especially careful to implement initialize in classes, because if it is implemented in classes, The Initialize method implemented by this class will not be called. In practice, the initialize method is used to initialize global or static variables.