Objective C类方法load和initialize的区别

2025-05-19 16:32:04
推荐回答(1个)
回答1:

 先来看看NSObject Class Reference里对这两个方法说明:

  +(void)initialize
  The runtime sends initialize to each class 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 this message before their subclasses.

  +(void)load
  The load message is sent to classes and categories that are both dynamically loaded and statically linked, but only if the newly loaded class or category implements a method that can respond.
  The order of initialization is as follows:

  All initializers in any framework you link to.
  All +load methods in your image.
  All C++ static initializers and C/C++ __attribute__(constructor) functions in your image.
  All initializers in frameworks that link to you.
  In addition:

  A class’s +load method is called after all of its superclasses’ +load methods.
  A category +load method is called after the class’s own +load method.
  In a custom implementation of load you can therefore safely message other unrelated classes from the same image, but any load methods implemented by those classes may not have run yet.

  Apple的文档很清楚地说明了initialize和load的区别在于:load是只要类所在文件被引用就会被调用,而initialize是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用;但即使类文件被引用进来,但是没有使用,那么initialize也不会被调用。

  它们的相同点在于:方法只会被调用一次。(其实这是相对runtime来说的,后边会做进一步解释)。

  文档也明确阐述了方法调用的顺序:父类(Superclass)的方法优先于子类(Subclass)的方法,类中的方法优先于类别(Category)中的方法。

  不过还有很多地方是文章中没有解释详细的。所以再来看一些示例代码来明确其中应该注意的细节。

  +(void)load与+(void)initialize初探
  复制代码
  1 +(void)load会引发+(void)initialize
  2 /******* Interface *******/
  3 @interface SuperClass : NSObject
  4 @end
  5
  6 @interface ChildClass : SuperClass
  7 @end
  8
  9 @interface Insideinitialize : NSObject
  10 - (void)objectMethod;
  11 @end
  12
  13 /******* Implementation *******/
  14 @implementation SuperClass
  15
  16 + (void) initialize {
  17 NSLog(@"%@ %s", [self class], __FUNCTION__);
  18 }
  19
  20 + (void) load {
  21 NSLog(@"%@ %s", [self class], __FUNCTION__);
  22 }
  23
  24 @end
  25
  26 @implementation ChildClass
  27
  28 + (void) initialize {
  29 NSLog(@"%@ %s", [self class], __FUNCTION__);
  30 Insideinitialize * obj = [[Insideinitialize alloc] init];
  31 [obj objectMethod];
  32 [obj release];
  33 }
  34
  35 @end
  36
  37 @implementation Insideinitialize
  38
  39 - (void)objectMethod {
  40 NSLog(@"%@ %s", [self class], __FUNCTION__);
  41 }
  42
  43 + (void) initialize {
  44 NSLog(@"%@ %s", [self class], __FUNCTION__);
  45 }
  46
  47 + (void) load {
  48 NSLog(@"%s", __FUNCTION__);
  49 }
  50
  51 @end
  复制代码
  

  这个示例代码中,一个SuperClass实现了+(void)load和+(void)initialize方法(实际上应该算是重写覆盖了NSObject的这两个方法);ChildClass继承于SuperClass,但是只重写+(void)initialize没有+(void)load;Insideinitialize类也有+(void)load和+(void)initialize方法,它在ChildClass的i+(void)initialize方法中被构建出一个对象。类中的每个函数的实现都非常简单,只是输出类名和方法名。除了Insideinitialize的+(void)load方法只输出了类名,没有使用[self class]。

  首先我们在Xcode的项目中只简单import这些类,而不去使用他们的,然后运行项目就会得到下边的结果:

  SuperClass +[SuperClass initialize]
  SuperClass +[SuperClass load]
  Insideinitialize +[Insideinitialize load]
  就像Apple的文档中说的一下,只要有引用runtime就会自动去调用类的+(void)load方法。不过从输出中,我们还发现SuperClass的+(void)initialize也被调用了,而且是在+(void)load之前被执行;而Insideinitialize的+(void)initialize并没有执行。这是因为在SuperClass的+(void)load方法中,我们调用了类的class方法([self class]),这就符合文档中对+(void)initialize的说明:在类的第一个方法被调用前调用。同时也说明runtime对+(void)load的调用并不视为类的第一个方法。而ChildClass因为没有用到,所以+(void)initialize的方法被没有被执行,而且它也没有去执行父类的+(void)load方法(虽然它有继承下该方法)。