单例模式

单例模式保证一个类只能拥有一个静态的实例,类负责创建与维护这个实例,并提供一个统一的静态(类方法)访问方式,并*了这个类外部的代码对这个类对象的创建。

.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:NULL] init];
 9     }
10     return _sharedInstance;
11 }
12 
13 +(id)allocWithZone:(struct _NSZone *)zone {
14     return [[self sharedInstance] retain];
15 }
单例模式

这里令人费解的是红字部分,为什么不直接alloc一个Singletone呢?

其实allocWithZone:Null就等价于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支持的不好,导致我们做了很多额外工作。

上面的代码不是线程安全的,如果需要保证单例对象的线程安全性,则需要写同步锁代码,一个使用GCD和ARC的例子在这里:

http://lukeredpath.co.uk/blog/a-note-on-objective-c-singletons.html

单例模式

上一篇:第一个UI界面


下一篇:Leetcode全树类问题