问题

对于某些类,我想在我的程序启动时显式调用 +initialize 方法,而不是允许运行时系统在稍后第一次使用该类时在某个不确定点隐式调用它。问题是,不推荐这样做。

我的大多数类在初始化时几乎没有工作要做,所以我可以让运行时系统为这些类做它的事情,但至少我的一个类需要多达 1 秒的时间在旧设备上进行初始化,而我不这样做不想在程序启动并运行时出现问题。 (一个很好的例子是音效——我不想在我第一次尝试播放声音时突然延迟。)

有哪些方法可以在启动时进行此初始化?

尝试的解决方案

我过去所做的是从 +initialize 手动调用 main.c 方法,并确保每个 +initialize 方法都有一个包装在 bool initialized 块中的 @synchronized 变量,以防止意外的双重初始化。但是现在 Xcode 警告我 +initialize 会被调用两次。这并不奇怪,但我不喜欢忽略警告,所以我宁愿解决这个问题。

我的下一个尝试(今天早些时候)是定义一个 +preinitialize 函数,我直接调用它而不是 +initialize ,并确保我在 +preinitialize 内部隐式调用 +initialize 以防在启动时没有显式调用它。但是这里的问题是 +preinitialize 内部的某些东西导致 +initialize 被运行时系统隐式调用,这让我认为这是一种非常不明智的方法。

因此,假设我想将实际的初始化代码保存在 +initialize (它真正想要的地方)中,并且只编写一个名为 +preinitialize 的微小虚拟方法,该方法强制运行时系统以某种方式隐式调用 +initialize?有没有标准的方法来解决这个问题?在单元测试中,我写了...

+ (void) preinitialize
{
  id dummy = [self alloc];
  NSLog(@"Preinitialized: %i", !!dummy);
}

...但在调试器中,我没有观察到 +initialize+alloc 之前被调用,这表明 +initialize 没有被 +preinitialize 内部的运行时系统隐式调用。

编辑

我找到了一个非常简单的解决方案,并将其发布为答案。

最佳答案

运行特定于类的代码的第一个可能位置是 +load ,当将类添加到 ObjC 运行时会发生这种情况。仍然不能完全确定以什么顺序调用哪些类的 +load 实现,但有一些规则。从文档:



因此,两个对等类(例如,两个直接的 NSObject 子类)在上面的第 2 步中都将是 +load,但不能保证它们之间的相对顺序。

正因为如此,并且因为 ObjC 中的元类对象通常不是设置和维护状态的好地方,你可能想要别的东西......

更好的解决方案?

例如,您的“全局”状态可以保存在单例类的(单个)实例中。客户端可以调用 [MySingletonClass sharedSingleton] 来获取该实例,而不用关心它是否在当时或更早完成了初始设置。如果客户端需要确保它更早发生(并且以相对于其他事物的确定性顺序),他们可以在他们选择的时间调用该方法——例如在启动 main/NSApplication 运行循环之前在 UIApplication 中。

备择方案

如果您不希望在应用程序启动时进行这种代价高昂的初始化工作,并且不希望在使用类时发生这种情况,那么您还有其他一些选择。

  • 将代码保存在 +initialize 中,并设法确保该类在第一次“真正”使用之前得到消息。例如,也许您可​​以启动后台线程以从 application:didFinishLaunching: 创建和初始化该类的虚拟实例。
  • 将该代码放在其他地方——在类对象或单例中,但无论如何都放在你自己创建的方法中——并在足够晚的时间直接调用它以进行设置以避免减慢应用程序启动但足够快在需要您的类(class)“真正”工作之前完成。
  • 关于Objective-C:如何在启动时而不是稍后在类第一次使用时强制调用 `+initialize`?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34799211/

    10-11 19:59