objective-c - NSObject +load 和 +initialize - 他们做什么

我有兴趣了解导致开发人员覆盖 +initialize 或 +load 的情况。文档清楚地说明了这些方法是由 Objective-C 运行时为您调用的,但是从这些方法的文档中可以清楚地看到这些。 :-)

我的好奇心来自于查看 Apple 的示例代码 - MVCNetworking。他们的模型类有一个 +(void) applicationStartup 方法。它在文件系统上做一些内务处理,读取 NSDefaults 等等……并且在尝试了解 NSObject 的类方法之后,看起来这项清洁工作可能可以放入 +load 中。

我确实修改了 MVCNetworking 项目,删除了 App Delegate 中对 +applicationStartup 的调用,并将管理位放入 +load... 我的计算机没有着火,但这并不意味着它是正确的!我希望了解您必须调用的自定义设置方法与 +load 或 +initialize 的任何微妙之处、陷阱和诸如此类的东西。


对于 +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.

如果你不知道所有单词的确切含义,这句话​​很杂乱,很难解析。救命!

  • “动态加载和静态链接”是什么意思?可以动态加载和静态链接,还是它们相互排斥?

  • "...新加载的类或类别实现了一个可以响应的方法"什么方法?如何回应?


至于 +initialize,文档说:

initialize it is invoked only once per class. If you want to perform independent initialization for the class and for categories of the class, you should implement load methods.

我的意思是,“如果你试图设置类......不要使用初始化。”好的。那么我何时或为什么要覆盖初始化?

最佳答案

加载消息

运行时将load 消息发送到每个类对象,在类对象加载到进程的地址空间后不久。对于作为程序可执行文件一部分的类,运行时会在进程生命周期的早期发送 load 消息。对于共享(动态加载)库中的类,运行时会在共享库加载到进程的地址空间后立即发送加载消息。

此外,如果类对象本身实现了 load 方法,则运行时仅将 load 发送到该类对象。示例:

@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

运行时将 load 消息发送到 Superclass 类对象。它确实load 消息发送到 Subclass 类对象,即使 Subclass 继承方法>父类(super class).

运行时将 load 消息发送到类的所有父类(super class)对象(如果这些父类(super class)对象实现 load) 以及您链接到的共享库中的所有类对象。但是您还不知道您自己的可执行文件中的哪些其他类已收到 load

如果你的进程加载到它的地址空间中的每个类都将收到一个 load 消息,如果它实现了 load 方法,无论你的进程是否有任何其他用途类(class)。

您可以在 objc-runtime-new.mm_class_getLoadMethod 中看到运行时如何将 load 方法作为特例查找。 , 并直接从 objc-loadmethod.mm 中的 call_class_loads 调用它.

运行时还运行它加载的每个类别的 load 方法,即使同一类上的多个类别实现 load。这是不寻常的。通常,如果两个类别在同一个类上定义了相同的方法,则其中一个方法将“获胜”并被使用,而另一个方法将永远不会被调用。

初始化方法

运行时在向类发送第一条消息(loadinitialize 除外)之前调用类对象的 initialize 方法对象或类的任何实例。该消息是使用正常机制发送的,因此如果您的类没有实现 initialize,而是从一个实现的类继承,那么您的类将使用其父类(super class)的 initialize。运行时将首先将 initialize 发送到类的所有父类(super class)(如果尚未发送父类(super class) initialize)。

例子:

@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;
}

这个程序打印两行输出:

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

由于系统延迟发送 initialize 方法,除非您的程序实际向类(或子类,或类或子类的实例)发送消息,否则类不会收到消息。当您收到 initialize 时,您进程中的每个类都应该已经收到 load(如果合适的话)。

实现initialize的规范方式是这样的:

@implementation Someclass

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

这种模式的重点是避免 Someclass 在其子类没有实现 initialize 时重新初始化自身。

运行时在objc-initialize.mm 中的_class_initialize 函数中发送initialize 消息.可以看到它使用objc_msgSend来发送,就是正常的消息发送功能。

进一步阅读

查看 Mike Ash's Friday Q&A关于这个话题。

关于objective-c - NSObject +load 和 +initialize - 他们做什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13326435/

相关文章:

ios - 将 Project-Swift.h 导入到 Objective-C 类中...找不到文件

ios - 使用 `textField:shouldChangeCharactersInRange:

objective-c - 如何向 NSDictionary 添加 bool 值?

objective-c - Objective-C 中的 protected 方法

ios - UILabel 中的动画文本更改

iphone - ARC 还是不 ARC?有什么优点和缺点?

ios - 将 UIButton 字体大小调整为宽度

objective-c - 使用 -performSelector : vs. 只是调用方法

objective-c - 未找到体系结构 i386 的符号

ios - 什么时候使用 NSSet 而不是 NSArray 更好?