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

How to properly implement ARC compatible and `alloc init` safe Singleton class?

本问题已经有最佳答案,请猛点这里访问。

我看到线程安全版本

1
2
3
4
5
6
7
8
9
+(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方法相同的实例?


Apple建议严格的单例实现(不允许使用同一类型的其他活动对象),方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+ (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;
}

链接到Apple文档(页面底部,无弧)


这可能会有所帮助,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
}


我从Duckrowing的博客上找到了这个代码示例:http://www.duckrowing.com/2011/11/09/using-the-singleton-pattern-in-objective-c-part-2/

在H中我们有

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

在M中我们有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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。