如何正确实现ARC兼容和`alloc init`安全的Singleton类?

时间:2013-07-23 11:45:25

标签: ios objective-c singleton automatic-ref-counting

我看到了线程安全版

+(MyClass *)singleton {
    static dispatch_once_t pred;
    static MyClass *shared = nil;

    dispatch_once(&pred, ^{
        shared = [[MyClass alloc] init];
    });
     return shared;
}

但如果有人打电话给[MyClass alloc] init]会怎么样?如何让它返回与+(MyClass *)singleton方法相同的实例?

3 个答案:

答案 0 :(得分:12)

Apple推荐严格的单例实现(不允许使用相同类型的其他生物对象):

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

+ (id)allocWithZone:(NSZone *)zone {
    return [self singleton];
}

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

链接到苹果documentation (bottom of page, Without ARC)

答案 1 :(得分:2)

这可能会有所帮助,

static Foo *sharedInstance = nil;

+ (Foo *)sharedInstance {

    if (sharedInstance == nil) {

        sharedInstance = [[super allocWithZone:NULL] init];
    }

    return sharedInstance;
}

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

答案 2 :(得分:0)

我从浏览博客中获取了此代码示例:http://www.duckrowing.com/2011/11/09/using-the-singleton-pattern-in-objective-c-part-2/

在.h中我们有

@interface Foo : NSObject
+ (Foo *) sharedFoo;
@end

在.m中我们有

static SLFoo *sharedInstance = nil;
static dispatch_queue_t serialQueue;

@implementation Foo

- (id)init
{
    id __block obj;

    dispatch_sync(serialQueue, ^{
        obj = [super init];
        if (obj) {
            ;
        }
    });

    self = obj;
    return self;
}

+ (Foo *) sharedFoo;
{
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        if (sharedInstance) {
            return;
        }
        sharedInstance = [[Foo alloc]init];
    });
    return sharedInstance;

}

+ (id)allocWithZone:(NSZone *)zone
{
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        serialQueue = dispatch_queue_create("com.mydomain.myApp.SerialQueueFoo", NULL);
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
        }
    });

    return sharedInstance;
}

@end

注意allocWithZone。