单例模式保证一个类只能拥有一个静态的实例,类负责创建与维护这个实例,并提供一个统一的静态(类方法)访问方式,并封锁了这个类外部的代码对这个类对象的创建。
.h文件:
1 #import <Foundation/Foundation.h> 2 3 @interface Singleton : NSObject 4 @property (nonatomic, copy) NSString *name; 5 + (Singleton *) sharedInstance; 6 @end
这里定义了一个类方法来获取单例对象的实例。
.m文件则比较复杂,首先要负责这个对象的创建:
1 #import "Singleton.h" 2 3 @implementation Singleton 4 5 static Singleton *_sharedInstance = nil; 6 + (Singleton *) sharedInstance { 7 if (_sharedInstance == nil) { 8 _sharedInstance = [[super allocWithZone:nil] init]; 9 } 10 return _sharedInstance; 11 } 12 13 +(id)allocWithZone:(struct _NSZone *)zone { 14 return [[self sharedInstance] retain]; 15 }
这里令人费解的是红字部分,为什么不直接alloc一个Singletone呢?
其实allocWithZone:nil就等价于alloc,只是这里alloc的是父类NSObject,这样做目的是把子类Singleton的allocWithZone拆解出去,拆解出来是为了复写。
之所以要复写,是为了堵住内存分配的漏洞,因为除了+sharedInstance方法之外,用户还可能在外部程序当中alloc一个Singleton对象,而OC语言并不支持java/C#当中的将构造函数私有化。
所以,子类复写allocWithZone的目的就显而易见、无需多言了。
到这里还没有结束,还需要堵住其他内存管理的漏洞,一是保证直接alloc的结果和使用sharedInstance方法的效果一样,二是令release无效:
1 -(id)copyWithZone:(NSZone *)zone { 2 return self; 3 } 4 5 -(id)init { 6 if (_sharedInstance) { 7 return _sharedInstance; 8 } 9 self = [super init]; 10 return self; 11 } 12 13 - (id)retain { 14 return self; 15 } 16 17 -(void)release { 18 // Do nothing 19 } 20 21 -(id)autorelease { 22 return self; 23 } 24 25 -(NSUInteger)retainCount { 26 return NSUIntegerMax; 27 }
这样就形成了一个中规中矩的、满足内存管理的单例模式,代码显得十分啰嗦,本质原因在于OC对private支持的不好,导致我们做了很多额外工作。
上面的代码不是线程安全的,如果需要保证单例对象的线程安全性,则需要写同步锁代码。
ARC下的单例相对简单:
1 + (id)sharedInstance 2 { 3 static dispatch_once_t pred = 0; 4 __strong static id _sharedObject = nil; 5 dispatch_once(&pred, ^{ 6 _sharedObject = [[self alloc] init]; // or some other init method 7 }); 8 return _sharedObject; 9 }
更有甚者搞了一个宏:http://lukeredpath.co.uk/blog/2011/07/01/a-note-on-objective-c-singletons/