我不太确定我在这个实现方面出了什么问题以及我需要进行哪些调整才能使加载的单例停留在内存中。
@implementation ApplicationSettings
static ApplicationSettings *sharedSettings = nil;
+ (void)load
{
@autoreleasepool {
sharedSettings = [self sharedSettings];
[self configureInitialSettings];
}
}
+ (ApplicationSettings*) sharedSettings {
if (sharedSettings)
return sharedSettings;
else {
return [[[ApplicationSettings alloc] init] autorelease];
}
}
- (void) dealloc {
[super dealloc];
}
这里显示了加载的主要方法,以及dealloc(我不使用ARC)。
我最近开始使用这种模式。我将不得不检查每个实施,以确保它是正确的。我发现了一个被解除分配并导致崩溃的案例。显然@autoreleasepool拥有它。我应该在return语句中删除autorelease,以便它不进入自动释放池吗?如果我这样做,那么它会被保留,直到程序被杀死,这对我没问题。那有什么不对吗?
答案 0 :(得分:1)
这不是声明单例类的正确方法。 (因此,您的+load
方法和对象保留不符合您在此处的使用情况,以及崩溃的原因)
+load
方法中加载单例实例是没用的,因为最好只在需要时分配实例,即首次请求它时(延迟加载)sharedSettings
方法中返回一个自动释放的实例会使单例模式无效并且无法实现其目的,因为您返回的实例将在自动释放池耗尽后立即释放(即在当前的RunLoop迭代结束时 - 如果你使用了任何内部@autoreleasepool
,如果不是更快的话。这很可能是导致你崩溃的原因!dealloc
的实现是无用的,首先是因为它只调用它的super
实现(所以你可以避免整个方法定义),并且因为你的类本来是一个单例,当您的应用程序处于活动状态时,实例永远不会从内存中释放。 当然,通常您需要通过alloc
或init
来电平衡release
和autorelease
次来电。这是内存管理的主要规则。但是对于Singleton模式,根据定义,单例的共享实例只要应用程序存在(这是主要角色)就存在,这是规则的例外,你不应该发布包含你的单例对象的sharedInstance,确保它能够继续生存并且不会从记忆中解除分配。
没有ARC的单身人士的一个正确(遗留)实施将重载alloc
/ retain
/ release
/ autorelease
/ retainCount
方法,正如关于单身人士的Apple文档中所述。但事实上,这些日子并不是我们这样做的方式,因为这个文档很旧(在GCD存在之前编写)并且过时了,并且因为 GCD现在提供了更好的替代方法,所以保证是线程-safe ,同时兼容非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,你无论如何都不能添加这些约束)。当您寻求Singleton模式时,您真正想要的是“在整个应用程序中共享的常见实例”,而不是“禁止创建多个实例的方式”,这就是我们在这里所拥有的。事实上,大多数自称为单身人士的课程就是这种情况(例如NSFileManager
)。