Objective-C单例实现,我做得对吗?

Objective-C单例实现,我做得对吗?,objective-c,singleton,Objective C,Singleton,在我的课堂上,我有 static Deck *gInstance = NULL; +(Deck *) instance { @synchronized(self) { if (gInstance == NULL) gInstance = [[self alloc] init]; } return (gInstance); } 还有一个init方法 -(id) init { if (gInstance != NULL

在我的课堂上,我有

static Deck *gInstance = NULL;


+(Deck *) instance {
    @synchronized(self) {
        if (gInstance == NULL)
            gInstance = [[self alloc] init];
    }

    return (gInstance);
}
还有一个init方法

-(id) init {

    if (gInstance != NULL) {
        return self;
    }

    self = [super init];

    if (self) {
       // Lots of clever things
    }
    gInstance = self;
    return self;

}
这里我主要关心的是
init
是否正确实现。请让我知道我写的东西是否适合你


或者。。。有没有一种方法可以使
init
私有化,并防止人们(包括我自己)看到它?

这是一种奇怪的单例实现。我最喜欢的实现是使用GCD中的一些较新功能

+ (MyObj*)sharedObject;
{
    static dispatch_once_t once;
    static MyObj *sharedObj;
    dispatch_once(&once, ^ { shared = [[MyObj alloc] init]; });
    return shared;
}
我建议只做那件事,不要多,不要少。强制执行严格的单例只能以痛苦告终,通常是毫无意义和反模式的


至于您的实现是否存在任何严格的“错误”,我相信您会希望在初始值设定项中返回
gInstance
,当它不是NULL而不是self时。

一般来说,您的构造函数不应该强制单一性。您的
实例
方法应该(确实如此)。这样做的原因是,您可能需要对象的单个实例以及创建对象的其他实例的能力

至于您提供的代码,您的
init
不是线程安全的。两个单独的线程可以分配给
gInstance
。首先设置它的线程将泄漏内存。可能会导致其他微妙的错误。例如,如果singleton是某种共享数据存储,那么赢得比赛的线程实际上会丢失与程序其余部分相关的数据

我提到线程安全的原因是,我个人遇到了许多与单线程以不安全的方式在多线程应用程序中使用有关的错误。所以,只有当您完全确定单例创建不会成为问题时,它才是线程不安全的

关于如何以线程安全的方式实现它,我看到了以下两种方法之一:

// first way
+ (Deck *)instance {
    static dispatch_once_t onceToken;
    static Deck *_shared;
    dispatch_once(&onceToken, ^{
        _shared = [[Deck alloc] init];
    });
    return _shared;
}

// second way
+ (Deck *)instance {
    static Deck *_shared;
    @synchronized(self) {
        if (_shared == nil) {
            _shared = [[Deck alloc] init];
        }
    }
    return _shared;
}

// init method
- (id)init {
    if ((self = [super init])) {
        // init stuff
    }
    return self;
}

使用
dispatch\u一次
需要libdispatch,这意味着最低操作系统为iOS 4.0或OS X 10.6。在此之前,使用
@synchronized(self)
应该可以在操作系统上使用。

你完全正确。非常感谢。很好的回访。我以前从来没有听说过GCD,你能推荐我复习一下吗?这是官方参考,Mike Ash一直都在讨论这一点,你试图强制使用私有初始值设定项的目的是什么?我来自Java世界,私有方法使得类的一个实例不可能被错误实例化。在Objective-C中没有真正私有的方法