【问题标题】:Where should I initialize my singleton in iOS/OS X app?我应该在 iOS/OS X 应用程序中在哪里初始化我的单例?
【发布时间】:2015-02-26 21:32:11
【问题描述】:

我想初始化我的单例对象,该对象在我的应用程序中存储和管理整个类的应用程序设置。此外,应该通过在启动时从NSUserDefaults 加载数据来初始化单例实例。但是,我不完全确定在启动时应该在哪里初始化单例。

在 Cocoa 应用程序中,我首先在 applicationWillFinishLaunching: 中编写了单例初始化代码,并从 NSUserDefaults 中获取参数。但是,后来我发现如果我还在故事板中设置的初始视图控制器中编写单例初始化代码(不带参数!),这将无法正常工作,因为类的viewWillLoad:viewDidLoad: 等视图控制器的名称applicationWillFinishLaunching:之前调用。

所以现在我确定我应该在viewWillLoad: 中编写单例初始化代码早于 applicationWillFinishLaunching,但仍然不确定它是否合适。具体来说,我知道NSApplicationMain 是启动时调用的第一个方法,但似乎下一个方法不是AppDelegate 中的任何内容,至少如果您使用情节提要。

总结一下,我想问的是:

  • 如果你使用故事板,在NSApplicationMain之后会调用什么类的什么方法。

  • 我应该在我的应用程序中的何处编写我的单例初始化代码?我想尽快初始化它。

  • iOS 和 OS X 应用程序有区别吗?

【问题讨论】:

  • 如果您需要,可以立即在initialize 中进行操作
  • 单例的美妙之处在于,至少从单例的角度来看,第一次引用单例的位置并不重要。单例的 sharedInstance 代码(或任何你称之为的代码)应该进行所有必要的配置,并且在代码中第一次遇到 sharedInstance 方法的任何地方都会进行此初始配置。
  • 感谢您的回答。尽快初始化它是不是很愚蠢?我认为它花费的时间非常非常少,并且可以改善维护......

标签: ios cocoa singleton uiapplicationdelegate


【解决方案1】:

您应该在第一次访问它时对其进行初始化。可能是这样的:

+ (instancetype)sharedInstance {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    _instance = [[self alloc] init];
  });
  return _instance;
}

附带说明一下,如果您实际上只是将此类用作NSUserDefaults 的访问器,您可能需要考虑使用静态方法。

+ (id)mySpecificDataPoint {
  return [[NSUserDefaults standardUserDefaults] objectForKey:@"whatever"];
}
+ (void)setMySpecificDataPoint:(id)data {
  [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"whatever"];
}

或者,一种设计更完善的方法可能是为此目的向NSUserDefaults 添加一个类别。

@interface NSUserDefaults (MyData)
@property (nonatomic) NSString *someDataPoint;
@property (nonatomic) NSInteger somePrimitiveDataPoint;
@end

@implementation NSUserDefaults (MyData)
- (NSString *)someDataPoint {
  return [self objectForKey:@"someDataPoint"];
}
- (void)setSomeDataPoint:(NSString *)someDataPoint {
  [self setObject:someDataPoint forKey:@"someDataPoint"];
}
- (NSInteger)somePrimitiveDataPoint {
  return [[self objectForKey:@"somePrimitiveDataPoint"] integerValue];
}
- (void)setSomePrimitiveDataPoint:(NSInteger)somePrimitiveDataPoint {
  [self setObject:@(somePrimitiveDataPoint) forKey:@"somePrimitiveDataPoint"];
}
@end

【讨论】:

  • 啊,我喜欢将单例实现的一部分作为NSUserDefaults! 的访问器的想法。我费心从用户默认值加载值并将其作为参数扔给单例的 init...谢谢。
  • 问题被标记为swift,但您的答案是用Objective-C编写的。也许你也可以用 Swift 代码更新你的答案?
  • @sbooth,删除了swift 标签。这个问题应该同时适用于 Swift 和 Objective-C。
【解决方案2】:

当你必须使用它时,你会初始化它。所以正如大吉 Djan 所说:懒惰获胜。请注意,您不应该在applicationWillFinishLaunching 中执行长期进程,它应该尽快返回。

如果在 applicationWillFinishLaunching 期间单例不是强制性的,如果需要尽快初始化,则应在第一个视图控制器的 viewWillAppear 中调用它。

【讨论】:

    【解决方案3】:

    懒惰总是赢

    如果你能侥幸成功:越晚越好 :) 并且总是做最少的事情(但要尽可能多地保持代码干净!)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-12
      • 1970-01-01
      • 2016-03-26
      • 2021-01-29
      • 2018-07-07
      • 2011-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多