+load and +initialize are common in iOS development. There are a lot of explanations for these two methods on the web, as well as official explanations, but some of the details are not clear. Today we will take a look at these two methods in detail.

load

The Apple documentation describes it this way

Invoked whenever a class or category is added to the Objective-C runtime; implement this method to perform class-specific behavior upon loading. When a Class or Category is added to the Runtime (that is, referenced). Implement this method to do some class-specific operations at load time. Discussion The load message is sent to classes and categories that are both dynamically loaded and statically linked, but onlyif the newly loaded class or category implements a method that can respond.

The order of initialization is as follows:

All initializers inAny framework you link to. Call All framework initializers All +load methodsinCall All +load methods All C++static initializers and C/C++ attribute(constructor) functions inCall C++ static initializers and attribute(constructor) functions in C/C++ All initializersinIn addition: A call to any initializations In the framework that link to the object fileclass's +load method is called after all of its superclasses. A class's +load method calls A category +load method after its parent's +load method is called after theclassThe +load method of a Category is called In a custom implementation of load you can therefore safely after the class whose +load method is extended message other unrelated classes from the same image, but any load methods implemented by those classes may not have run yet. In the +load method, it is safe to send messages to other unrelated classes in the same binary package, but the + Load method in the class receiving the message may not have been called yet.Copy the code

The document address: https://developer.apple.com/reference/objectivec/nsobject/1418815-load?language=objc

The load function call features the following:

The load function is called when a class is referenced in a project (before main starts executing), regardless of whether the class is used or not; each class’s load function is called automatically only once. Since the load function is automatically loaded by the system, there is no need to call the load function of the parent class. Otherwise, the load function of the parent class will be executed multiple times.

  • 1. When both a parent class and a child class implement the load function, the load method of the parent class takes precedence over that of the child class
  • 2. When a subclass does not implement the load method, the parent class load method is not called
  • 3. The load method of the class should be executed in precedence over the Category.
  • 4. When multiple categories implement load methods, they will all be executed in an uncertain order (the order of execution is the same as that of the categories in Compile Sources).
  • 5. Of course, when there are multiple different classes, each class load is executed in the same order as it appears in Compile Sources

Here is an example to verify:

We create two new classes :Person inherits from NSObject, and Student and Teacher both inherit from Person


Person : NSObject
Student : Person
Teacher : Person
Copy the code

Create 3 new Person categories:

Person (Category)
Person (Category2)
Person (Category3)
Copy the code

Implement the following methods (except Teacher) in the.m files of Person,Student,Person (Category),Person (Category2),Person (Category3)

//In Person.m+ (void)load
{
    NSLog(@"%s",__FUNCTION__);
}
//In Student. M (inherited from Person)+ (void)load
{
    NSLog(@"%s",__FUNCTION__);
}

//In Teacher. M (inherit Person)The load method is not implemented//In Person+Category.m+ (void)load
{
    NSLog(@"%s",__FUNCTION__);
}
//In Person+Category2.m+ (void)load
{
    NSLog(@"%s",__FUNCTION__);
}
//In Person+Category3.m+ (void)load
{
    NSLog(@"%s",__FUNCTION__);
}

Copy the code

Running results:


2017- 05- 04 11:11:40.612 LoadAndInitializeExample[27745:856244] +[Person load]
2017- 05- 04 11:11:40.615 LoadAndInitializeExample[27745:856244] +[Student load]
2017- 05- 04 11:11:40.616 LoadAndInitializeExample[27745:856244] +[Person(Category3) load]
2017- 05- 04 11:11:40.617 LoadAndInitializeExample[27745:856244] +[Person(Category) load]
2017- 05- 04 11:11:40.617 LoadAndInitializeExample[27745:856244] +[Person(Category2) load]

Copy the code

It can be seen that the execution sequence is as follows:

  • Person load (); Student load (); Person load (); Student load ()
  • 2. There is no load method in the subclass Teacher and no printing, indicating that the parent class load method will not be called when the subclass load method is not implemented
  • 3. Finally, the load methods of the three categories of Person are executed without order, indicating that the load methods in the Category are later than the class. Multiple categories have implemented load methods, and all these load methods will be executed, but the execution order is uncertain
  • 4. At the same time, we can also see that these Category loads are executed in the same order as those in Compile Sources
  • 5. Of course, the load execution order of multiple different classes is the same as that in Compile Sources

initialize:

The Apple documentation describes it this way

Initializes the classbefore it receives its first message. Called before the class receives the first message. Discussion The runtime sends initialize to eachclass in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Thus the method may never be invoked if the class is not used.) The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive thisMessage before their subclasses. Runtime Sending an initialization once in a program for each class in a program, or in any class it inherits from, is sending the first message in the program. (Therefore, the method may never be called when the class is not in use.) The runtime sends a thread-safe initialization message. The parent class must be called before the child class.Copy the code

The document address: https://developer.apple.com/reference/objectivec/nsobject/1418639-initialize?language=objc

The initialize function calls have the following characteristics:

Initialize is called before the first method of the class or its subclass is called. Initialize is not called even if the class file is referenced in the project but not used. [super Initialize] does not need to be called because it is automatically called by the system. Otherwise, the initialize of the parent class will be executed multiple times. If the class is placed in code that is not executed, the function will not be executed.

  • 1. The initialize method of the parent class executes before that of the subclass
  • 2. If a subclass does not implement the initialize method, the parent class initialize method is called. If a subclass implements the initialize method, the parent class initialize method is overwritten.
  • The initialize method is overwritten by the class when multiple categories implement the initialize method, and only one of them is executed (the last Category in the Compile Sources list is executed).

Let’s also verify it with an example:

We add the Person class and implement the + Initialize method in.m

//In Person.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}

Copy the code

Running results:

No printing...Copy the code

Nothing was printed

Note: Only the class file is referenced in the project. Initialize will not be called if it is not used

We do not implement the initialize method in Teacher(inherits Person).m


//In Person.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}

//In Teacher. M (inherited from Person)Teacher. M does not implement the initialize methodCopy the code

Let’s call Teacher’s new method and run


[Teacher new];

Copy the code

Running results:

2017- 05- 04 14:06:45.051 LoadAndInitializeExample[29238:912579] +[Person initialize]
2017- 05- 04 14:06:45.051 LoadAndInitializeExample[29238:912579] +[Person initialize]
Copy the code

The initialize method of the parent class is called twice:

The initialize method is called when the subclass does not implement the initialize method.

But why print it twice?

Subclasses do not implement the initialize method. Instead, subclasses inherit the initialize method from their parent class and call it once. Before that, the parent class first calls its initialize method. To prevent the code from being executed more than once in initialize, we should write:

//In Person.m+ (void)initialize
{
	if(self == [Person class])
	{
          NSLog(@"%s",__FUNCTION__); }}Copy the code

Let’s implement the initialize method in teacher.m

//In Person.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}

//In Teacher. M (inherited from Person)+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}

Copy the code

Also call Teacher’s new method, run


[Teacher new];

Copy the code

Running results:

2017- 05- 04 14:07:45.051 LoadAndInitializeExample[29238:912579] +[Person initialize]
2017- 05- 04 14:07:45.051 LoadAndInitializeExample[29238:912579] +[Teacher initialize]
Copy the code

As you can see, when a subclass implements the Initialize method, it overrides the initialize method of its parent class, just like inheritance

We implement the Initialize method in person. m and Person+ category. m

//In Person.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}

//In Person+Category.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}

Copy the code

Call the New method of Person and run

[Person new];

Copy the code

Running results:

2017- 05- 05 09:46:51.054 LoadAndInitializeExample[38773:1226306] +[Person(Category) initialize]
Copy the code

When run, you can see that the Initialize method of Person is not executed and has been replaced by initialize in Person+Category

What happens when we have multiple categories and we implement the Initialize method in the.m of Person,Person+Category,Person+Category2, and Person+Category3

//In Person.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}

//In Person+Category.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}
//In Person+Category2.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}
//In Person+Category3.m+ (void)initialize
{
     NSLog(@"%s",__FUNCTION__);
}

Copy the code

Call the Person New method and run

[Person new];
Copy the code

Running results:

2017- 05- 05 09:49:38.853 LoadAndInitializeExample[38825:1227819] +[Person(Category2) initialize]
Copy the code

The initialize method of the last Category in the Compile Sources list will be executed after the initialize method is executed

When to use:

####+load

Since the load method is called in an insecure environment, we should minimize the logic of the load method. Another reason is that the Load method is thread-safe and uses locks internally, so we should avoid thread blocking in the Load method

A common use scenario for load is to swap implementations of the two methods

/ / from MJRefresh
+ (void)load
{
    [self exchangeInstanceMethod1:@selector(reloadData) method2:@selector(mj_reloadData)];
    [self exchangeInstanceMethod1:@selector(reloadRowsAtIndexPaths:withRowAnimation:) method2:@selector(mj_reloadRowsAtIndexPaths:withRowAnimation:)];
    [self exchangeInstanceMethod1:@selector(deleteRowsAtIndexPaths:withRowAnimation:) method2:@selector(mj_deleteRowsAtIndexPaths:withRowAnimation:)];
    [self exchangeInstanceMethod1:@selector(insertRowsAtIndexPaths:withRowAnimation:) method2:@selector(mj_insertRowsAtIndexPaths:withRowAnimation:)];
    [self exchangeInstanceMethod1:@selector(reloadSections:withRowAnimation:) method2:@selector(mj_reloadSections:withRowAnimation:)];
    [self exchangeInstanceMethod1:@selector(deleteSections:withRowAnimation:) method2:@selector(mj_deleteSections:withRowAnimation:)];
    [self exchangeInstanceMethod1:@selector(insertSections:withRowAnimation:) method2:@selector(mj_insertSections:withRowAnimation:)];
}

+ (void)exchangeInstanceMethod1:(SEL)method1 method2:(SEL)method2
{
    method_exchangeImplementations(class_getInstanceMethod(self, method1), class_getInstanceMethod(self, method2));
}
Copy the code

The ####+initialize initialize method is used to assign values to objects that are not easily initialized at compile time. An instantiation of the NSMutableArray type, for example, depends on the runtime sending of messages, so it obviously cannot be initialized at the compiler:


// In Person.m
// Int can be assigned at compile time
static int someNumber = 0; 
static NSMutableArray *someArray;
+ (void)initialize {
    if (self == [Person class]) {
        // It is inconvenient to assign values to objects copied at compile time
        someArray = [[NSMutableArrayalloc] init]; }}Copy the code

Conclusion:

Load and Initialize have in common

1. If both a parent class and a subclass are called, the parent class must be called before the subclass

+load method essentials

The load function is called when a class is referenced in a project (before main starts executing), regardless of whether the class is used or not; each class’s load function is called automatically only once. Since the load function is automatically loaded by the system, there is no need to call [super Load], otherwise the load function of the parent class will be executed multiple times.

  • 1. When both a parent class and a child class implement the load function, the load method of the parent class takes precedence over that of the child class
  • 2. When a class does not implement a load method, the parent class load method is not called
  • 3. The load method of the class should be executed in precedence over the Category.
  • 4. When multiple categories implement load methods, they will all be executed in an uncertain order (the order of execution is the same as that of the categories in Compile Sources).
  • 5. Of course, when there are multiple different classes, each class load is executed in the same order as it appears in Compile Sources

The load method is thread safe, it uses a lock, and we should avoid thread blocking in the load method.


+initialize method essentials

Initialize is called before the first method of the class or its subclass is called. Initialize is not called even if the class file is referenced in the project but not used. Since this is an automatic call, there is no need to explicitly call initialize of the parent class; otherwise, initialize of the parent class will be executed multiple times. If the class is placed in code that is not executed, the function will not be executed.

  • 1. The initialize method of the parent class executes before that of the subclass
  • 2. When a subclass does not implement initialize, it inherits the parent class’s implementation and calls it. Before that, the methods of the parent class are called first
  • The initialize method is overwritten by the class when multiple categories implement the initialize method, and only one of them is executed (the last Category in the Compile Sources list is executed).

Note: When the Initialize method is called, the runtime environment is basically sound. Initialize also uses locks internally, so it is thread-safe. But in the meantime, avoid blocking threads and stop using locks


The above summary may not be complete, welcome to leave a message to add….. Code address :github.com/CoderZhuXH/…