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