我应该在 iOS/OS X 应用程序中在哪里初始化我的单例?

Posted

技术标签:

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

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

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

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

总结一下,我想问的是:

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

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

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

【问题讨论】:

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

懒惰总是赢

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

【讨论】:

以上是关于我应该在 iOS/OS X 应用程序中在哪里初始化我的单例?的主要内容,如果未能解决你的问题,请参考以下文章

在同构 Redux 应用程序中在哪里设置 cookie?

在 React 应用程序中在哪里转换数据 - 在 Express 中还是在前端使用 React?

在基于 Web 的前端中在哪里实现后端过滤器逻辑

使用复制列表初始化从函数返回,不需要复制/移动构造函数 - C++ 11 标准中在哪里说明?

在 redux 中在哪里调度多个操作?

在 android studio java 代码中在哪里声明视图?声明应该在 onCreate 函数外部还是内部完成