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; } |
但如果有人打电话给
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。