Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 目标C:如何强制呼叫+;initialize`在启动时而不是在类第一次使用时初始化? 问题_Objective C_Initialization_Startup - Fatal编程技术网

Objective c 目标C:如何强制呼叫+;initialize`在启动时而不是在类第一次使用时初始化? 问题

Objective c 目标C:如何强制呼叫+;initialize`在启动时而不是在类第一次使用时初始化? 问题,objective-c,initialization,startup,Objective C,Initialization,Startup,对于某些类,我希望在程序启动时显式调用+initialize方法,而不是允许运行时系统在稍后首次使用该类时的某个不确定点隐式调用它。问题是,不建议这样做 我的大多数类在初始化时几乎没有什么工作要做,所以我可以让运行时系统来完成它的工作,但至少我的一个类需要1秒钟才能在旧设备上初始化,我不希望以后程序启动并运行时出现问题。(声音效果就是一个很好的例子——我不想在第一次尝试播放声音时突然延迟。) 在启动时进行初始化的一些方法是什么 尝试的解决方案 我在过去所做的是从main.c手动调用+initia

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

我的大多数类在初始化时几乎没有什么工作要做,所以我可以让运行时系统来完成它的工作,但至少我的一个类需要1秒钟才能在旧设备上初始化,我不希望以后程序启动并运行时出现问题。(声音效果就是一个很好的例子——我不想在第一次尝试播放声音时突然延迟。)

在启动时进行初始化的一些方法是什么

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

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

假设我想将实际的初始化代码保存在
+initialize
(它真正想要的地方)中,然后只编写一个名为
+preinitialize
的小虚拟方法,强制运行时系统以某种方式隐式调用
+initialize
?有没有一个标准的方法?在单元测试中,我写道

+ (void) preinitialize
{
  id dummy = [self alloc];
  NSLog(@"Preinitialized: %i", !!dummy);
}
…但是在调试器中,我没有观察到在
+alloc
之前调用
+initialize
,这表明
+initialize
内部的运行时系统没有隐式调用
+preinitialize

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

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

初始化的顺序如下:

  • 链接到的任何框架中的所有初始值设定项

  • 所有
    +加载图像中的
    方法

  • > P>所有C++静态初始化器和C/C++ +COD> 图像中的函数

  • 框架中链接到您的所有初始值设定项

  • 此外:

    • 类的
      +load
      方法在其所有超类的
      +load
      方法

    • 在类自己的
      +load
      方法之后调用category
      +load
      方法

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

    正因为如此,而且由于ObjC中的元类对象通常不是设置和维护状态的好地方,所以您可能需要其他东西

    更好的解决方案? 例如,您的“全局”状态可以保存在单例类的(单个)实例中。客户端可以调用
    [MySingletonClass sharedSingleton]
    来获取该实例,而不关心它是在那个时候还是更早的时候完成了初始设置。如果客户机需要确保它发生得更早(并且以相对于其他事物的确定顺序),他们可以在自己选择的时间调用该方法-例如在
    main
    中,然后启动
    NSApplication
    /
    UIApplication
    运行循环

    选择 如果您不希望这种昂贵的初始化工作在应用程序启动时发生,也不希望在类投入使用时发生,那么您还有一些其他选择

    • 将代码保存在
      +initialize
      中,并设法确保类在第一次“真正”使用之前收到消息。例如,您可以启动一个后台线程,从
      应用程序:didFinishLaunching:
      创建并初始化该类的虚拟实例
    • 将代码放在其他地方-在类对象或单例中,但无论如何都要放在自己创建的方法中-并在足够晚的时间直接调用它,以便安装程序避免减慢应用程序启动,但足够快,以便在需要类的“真正”工作之前完成

    Cocoa以的形式提供早于
    +initialize
    的设置点,该设置点在程序启动后不久调用。这是一个奇怪的环境:依赖
    +load
    的其他类可能尚未完全初始化,更重要的是,您的
    main()
    !这意味着没有自动释放池

    加载
    之后但在
    初始化
    之前,将调用标有
    \uuuu属性((构造函数))
    的函数。就我所知,这不允许你做很多在
    main()
    中做不到的事情

    一个选项是在
    main()
    @interface Foo: NSObject
    + (void)setup;
    @end
    
    @implementation Foo
    
    + (void)setup {
        NSLog(@"Setup start");
    
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSLog(@"Setup running");
            [NSThread sleepForTimeInterval:1]; // Expensive op
        });
    }
    @end
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        NSLog(@"START");
    
        // Here, you should setup your UI into an "inactive" state, since we can't do things until
        // we're done initializing.
    
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
            [Foo setup];
            // And any other things that need to intialize in order.
        });
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"We're all ready to go now! Turn on the the UI. Set the variables. Do the thing.");
        });
        return YES;
    }
    
    #if !defined(NS_BLOCK_ASSERTIONS)
    #define FooAssertInitialized(condition) NSAssert([Foo isInitialized], @"You must call +setup before using Foo.")
    #else
    #define FooAssertInitialized(condition)
    #endif
    
    - (void)someMethodThatRequiresInitialization {
        FooAssertInitialized();
    
        // Do stuff
    }
    
    (void)[MyClass class];
    
    + (void) preinitialize
    {
      // Simply by calling this function at startup, an implicit call to
      // +initialize is generated.
    }
    
    [MyClass preinitialize];  // Implicitly invokes +initialize.