kongkong's Blog

No Silver Bullet --- Computer Language is just a tool.

iOS中的Initialize 和 load方法

| Comments

总结:

  • Objective-C 提供两种方法to automatically run class-setup code, 两者都在Main方法未调用前被执行,+load方法需要显式地实现才会被调用,不会从父类继承。+initialize如果子类不实现也会从父类继承,所以会出现重复执行的情况。所以,you should always write your +initialize method to look like this:
     + (void)initialize
    {
        if(self == [WhateverClass class])
        {
            ...perform initialization...
        }
    }
    
  • +initialize方法更适合做setup tasks, 因为it runs lazily(指的是会从父类直接继承并执行) and in a nice environment.

注:下面的内容转自stackOverFlow iOS中的Initialize 和 load方法

The load message

The runtime sends the load message to each class object, very soon after the class object is loaded in the process's address space. For classes that are part of the program's executable file, the runtime sends the load message very early in the process's lifetime. For classes that are in a shared (dynamically-loaded) library, the runtime sends the load message just after the shared library is loaded into the process's address space.

Furthermore, the runtime only sends load to a class object if that class object itself implements the load method. Example:

@interface Superclass : NSObject
@end

@interface Subclass : Superclass
@end

@implementation Superclass

+ (void)load {
    NSLog(@"in Superclass load");
}

@end

@implementation Subclass

// ... load not implemented in this class

@end

The runtime sends the load message to the Superclass class object. It does not send the load message to the Subclass class object, even though Subclass inherits the method from Superclass.

The runtime sends the load message to a class object after it has sent the load message to all of the class's superclass objects (if those superclass objects implement load) and all of the class objects in shared libraries you link to. But you don't know which other classes in your own executable have received load yet.

Every class that your process loads into its address space will receive a load message, if it implements the load method, regardless of whether your process makes any other use of the class.

You can see how the runtime looks up the load method as a special case in the class_getLoadMethod of objc-runtime-new.mm, and calls it directly from callclass_loads in objc-loadmethod.mm.

The runtime also runs the load method of every category it loads, even if several categories on the same class implement load. This is unusual. Normally, if two categories define the same method on the same class, one of the methods will “win” and be used, and the other method will never be called.

The initialize Method

The runtime sends the initialize method to a class object just before sending the first message (other than load or initialize) to the class object or any instances of the class. This message is sent using the normal mechanism, so if your class doesn't implement initialize, but inherits from a class that does, then your class will use its superclass's initialize. The runtime will send the initialize to all of a class's superclasses first (if the superclasses haven't already been sent initialize).

Example:

@interface Superclass : NSObject
@end

@interface Subclass : Superclass
@end

@implementation Superclass

+ (void)initialize {
    NSLog(@"in Superclass initialize; self = %@", self);
}

@end

@implementation Subclass

// ... initialize not implemented in this class

@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        Subclass *object = [[Subclass alloc] init];
    }
    return 0;
}

This program prints two lines of output:

2012-11-10 16:18:38.984 testApp[7498:c07] in Superclass initialize; self = Superclass
2012-11-10 16:18:38.987 testApp[7498:c07] in Superclass initialize; self = Subclass

Since the system sends the initialize method lazily, a class won't receive the message unless your program actually sends messages to the class (or a subclass, or instances of the class or subclasses). And by the time you receive initialize, every class in your process should have already received load (if appropriate).

The canonical way to implement initialize is this:

@implementation Someclass

+ (void)initialize {
    if (self == [Someclass class]) {
        // do whatever
    }
}

The point of this pattern is to avoid Someclass re-initializing itself when it has a subclass that doesn't implement initialize.

The runtime sends the initialize message in the class_initialize function in objc-initialize.mm. You can see that it uses objcmsgSend to send it, which is the normal message-sending function.

Further reading

Check out Mike Ash's Friday Q&A on this topic.

Comments

comments powered by Disqus