这不是声明单例类的正确方法。(因此,您的+load
方法和对象保留不适合您在此处的使用以及崩溃的原因)
- 在方法中加载单例实例
+load
是没有用的,因为最好只在需要时分配实例,即在第一次请求时(延迟加载)
- 但更重要的是,在方法中返回一个自动释放的实例
sharedSettings
会使单例模式无效并无法达到其目的,因为您返回的实例将在自动释放池耗尽时立即释放(即在当前 RunLoop 迭代结束时) - 如果你有任何内部@autoreleasepool
使用,如果不是更早)。这很可能是你崩溃的原因!
- 的实现
dealloc
是无用的,首先因为它只调用它的super
实现(这样你可以避免整个方法定义),并且因为你的类是一个单例,当你的应用程序还活着时,实例永远不会从内存中释放。
- 最后但并非最不重要的一点是,您的实现根本不是线程安全的。
当然,通常你需要平衡alloc
和init
调用release
或autorelease
调用。这是内存管理的主要规则。但是对于单例模式,根据定义,只要应用程序存在(这是主要角色),单例的共享实例就会存在,这是规则的例外,您不应释放包含单例对象的 sharedInstance,以确保它继续存在并且不会从内存中释放。
没有 ARC 的单例的一种正确(传统)实现是重载alloc
/ retain
/ release
/ autorelease
/retainCount
方法,如 Apple 关于单例的文档中所述。但事实上,这并不是我们现在真正这样做的方式,因为这个文档已经很老了(在 GCD 存在之前编写)并且已经过时,而且GCD 现在提供了一种更好的替代方案,即保证线程安全,并且也与非ARC和ARC兼容(而后者在ARC环境下无法实现)。所以这里是:
@implementation ApplicationSettings
+(ApplicationSettings*)sharedInstance
{
static ApplicationSettings* sharedInstance = nil;
static dispatch_once_t once;
dispatch_once(&once, ^{ sharedInstance = [[self alloc] init]; });
return sharedInstance;
}
@end
就这样。不需要方法之外的全局变量或其他任何东西。只需声明此方法并在每次需要访问单例时使用它即可。如果您需要填充单例的一些实例变量,就像您可能在您的configureInitialSettings
方法中所做的那样,只需在init
您的单例的方法中完成,就像您在标准类中做的那样。
附加说明:如果您想非常严格,有些人可能会争辩说它不会禁止使用 alloc/init 分配/创建该类的其他实例(您自己的实现也不会在您的问题中)所以这不是真正的单例:如果她/他真的想要,仍然可以分配它的多个实例。
但在实践中,即使这是真的,我也看不出有什么理由要真正添加这些约束(如果有一天你切换到 ARC,你无论如何都不能添加这些约束)。当您寻求单例模式时,您真正想要的更多是“在整个应用程序中共享的公共实例”,而不是“一种禁止创建多个实例的方法”,这就是我们在这里所拥有的。实际上,对于大多数声称是单例的类(NSFileManager
例如)来说,情况就是如此。