使用NSObject加载方法正确保留对象



我不太确定这个实现哪里出了问题,也不太确定需要做什么调整才能使加载的单例留在内存中。

@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];
}

这里显示了加载的主要方法,以及解除锁定(我不使用ARC)。

我最近开始使用这种模式。我必须检查每个实现,以确保它是正确的。我发现了一个案例,它被释放并导致崩溃。很明显,@autoreleasepool拥有它。我应该删除return语句中的autorelease,这样它就不会进入autoreleasepool吗?如果我这样做,那么它会一直保留到程序被终止,这对我来说很好。这有什么错吗?

这不是声明单例类的正确方法。(因此,您的+load方法和对象保留不符合您在这里的使用,以及崩溃的原因)

  • +load方法中加载singleton实例是没有用的,因为最好只在需要时分配实例,也就是第一次请求时(延迟加载)
  • 但更重要的是,在sharedSettings方法中返回一个自动释放的实例会使单例模式无效并无法实现其目的,因为您返回的实例将在自动释放池耗尽后立即释放(即在当前RunLoop迭代结束时,如果您使用了任何内部@autoreleasepool,则不会更早)。这很可能是你撞车的原因
  • dealloc的实现是无用的,首先是因为它只调用它的super实现(这样你就可以避免整个方法定义),而且因为你的类是单例的,所以当你的应用程序运行时,实例永远不会从内存中释放
  • 最后但同样重要的是,您的实现根本不是线程安全的

当然,通常您需要平衡allocinit调用与releaseautorelease调用。这是内存管理的主要规则。但对于Singleton模式,根据定义,Singleton的共享实例的寿命与应用程序的寿命一样长(这是主要角色),这是规则的例外,您不应该释放包含Singleton对象的sharedInstance,以确保它继续存在,并且不会从内存中释放


对于没有ARC的singleton,一个正确的(遗留的)实现是重载alloc/retain/release/autorelease/retainCount方法,正如Apple关于singleton的文档中所解释的那样。但事实上,现在我们已经不是这样做了,因为这个文档已经很旧了(在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

仅此而已。不需要方法之外的全局变量或其他任何变量。只需声明这个方法,并在每次需要访问singleton时使用它就可以了。如果您需要填充singleton的一些实例变量,那么,就像您可能在configureInitialSettings方法中所做的那样,只需在singleton的init方法中进行即可,就像在标准类中一样。


额外注意:如果你想非常严格,有些人可能会争辩说,它不会禁止使用alloc/init分配/创建类的其他实例(在你的问题中,你自己的实现也不会),所以这不是一个真正的单例:如果你真的想,你仍然可以分配它的多个实例。

但在实践中,即使这是真的,我也看不出有任何理由真正添加这些约束(如果有一天你切换到ARC,你无论如何都无法添加这些约束)。当您寻求Singleton模式时,您真正想要的更多的是"在整个应用程序中共享一个公共实例",而不是"禁止创建多个实例的方法",这就是我们在这里所拥有的。事实上,大多数声称是Singleton的类(例如NSFileManager)都是这样。

最新更新