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

时间:2011-11-18 03:30:11

标签: 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) {
        return self;
    }

    self = [super init];

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

}

我在这里关注的主要是init是否正确实施。如果我写的内容适合你,请告诉我。

或者......有没有办法可以让init私密并阻止人们(包括我自己)完全看到它?

2 个答案:

答案 0 :(得分:6)

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

+ (MyObj*)sharedObject;
{
    static dispatch_once_t once;
    static MyObj *sharedObj;
    dispatch_once(&once, ^ { shared = [[MyObj alloc] init]; });
    return shared;
}

我建议只做这件事,仅此而已。强制执行一个严格的单身人士只会痛苦地结束,而且通常是毫无意义的反模式。

如果您的实现存在任何严格“错误”的错误,我相信您希望在初始化程序中返回gInstance,而不是自我。

答案 1 :(得分:1)

通常,构造函数不应强制执行单一性。你的instance方法应该(它做的)。这样做的原因是您可能需要对象的单例以及创建对象的其他实例的能力。

至于您提供的代码init不是线程安全的。可以将两个单独的线程分配给gInstance。首先设置它的线程会泄漏内存。而其他微妙的错误可能会导致。例如,如果单例是某种共享数据存储区,则赢得竞争的线程将有效地使其数据相对于程序的其余部分丢失。

我之所以提到线程安全,是因为我个人遇到过很多与单线程有关的错误,它们以不安全的方式用于多线程应用程序。因此,如果你绝对确定它不会成为一个问题,那么只有单例创建才是线程不安全的。

就如何以线程安全的方式实现它,我已经看到它中的一个说:

// 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_once需要libdispatch,这意味着iOS 4.0或OS X 10.6的最低操作系统。在此之前使用@synchronized(self)应该适用于操作系统。