我的单例访问方法通常是一些变种:

static MyClass *gInstance = NULL;

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

    return(gInstance);
}

我能做些什么来改善这一点呢?


当前回答

对于Objective C类方法,我们可以避免以通常的方式使用单例模式,如下所示:

[[Librarian sharedInstance] openLibrary]

to:

[Librarian openLibrary]

通过将类包装到另一个只有类方法的类中,这样就不会意外地创建重复的实例,因为我们没有创建任何实例!

我在这里写了一篇更详细的博客:)

其他回答

对于Objective C类方法,我们可以避免以通常的方式使用单例模式,如下所示:

[[Librarian sharedInstance] openLibrary]

to:

[Librarian openLibrary]

通过将类包装到另一个只有类方法的类中,这样就不会意外地创建重复的实例,因为我们没有创建任何实例!

我在这里写了一篇更详细的博客:)

我通常使用的代码大致类似于Ben Hoffstein的回答(这也是我从维基百科上得到的)。我使用它的原因是Chris Hanson在他的评论中提到的。

然而,有时我需要将一个单例放入NIB中,在这种情况下,我使用以下方法:

@implementation Singleton

static Singleton *singleton = nil;

- (id)init {
    static BOOL initialized = NO;
    if (!initialized) {
        self = [super init];
        singleton = self;
        initialized = YES;
    }
    return self;
}

+ (id)allocWithZone:(NSZone*)zone {
    @synchronized (self) {
        if (!singleton)
            singleton = [super allocWithZone:zone];     
    }
    return singleton;
}

+ (Singleton*)sharedSingleton {
    if (!singleton)
        [[Singleton alloc] init];
    return singleton;
}

@end

我把-retain(等等)的实现留给读者,尽管在垃圾收集环境中您只需要上面的代码。

根据我下面的另一个回答,我认为你应该这样做:

+ (id)sharedFoo
{
    static dispatch_once_t once;
    static MyFoo *sharedFoo;
    dispatch_once(&once, ^ { sharedFoo = [[self alloc] init]; });
    return sharedFoo;
}

简单回答:太棒了。

长话短说:类似....

static SomeSingleton *instance = NULL;

@implementation SomeSingleton

+ (id) instance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (instance == NULL){
            instance = [[super allocWithZone:NULL] init];
        }
    });
    return instance;
}

+ (id) allocWithZone:(NSZone *)paramZone {
    return [[self instance] retain];
}

- (id) copyWithZone:(NSZone *)paramZone {
    return self;
}

- (id) autorelease {
    return self;
}

- (NSUInteger) retainCount {
    return NSUIntegerMax;
}

- (id) retain {
    return self;
}

@end

一定要阅读dispatch/once.h头文件以了解发生了什么。在这种情况下,标题注释比文档或手册页更适用。

这不应该是线程安全的,避免第一次调用后昂贵的锁定吗?

+ (MySingleton*)sharedInstance
{
    if (sharedInstance == nil) {
        @synchronized(self) {
            if (sharedInstance == nil) {
                sharedInstance = [[MySingleton alloc] init];
            }
        }
    }
    return (MySingleton *)sharedInstance;
}