1、前言
单例是一种类,该类只在第一次用的时候实例化一个对象,后期直接调用此对象。
在Foundation框架中比如NSFileManger和NSNotificationCenter,分别通过它们的类方法defaultManager和defaultCenter获取。尽管不是严格意义的单例,这些类方法返回一个可以在应用的所有代码中访问到的类的共享实例。
2、原理
单例函数dispatch_once:
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
该函数接收一个dispatch_once用于检查该代码块是否已经被调度的谓词(是一个长整型,实际上作为BOOL使用)。
还接收一个希望在应用的生命周期内仅被调度一次的代码块,对于本例就用于shared实例的实例化。
dispatch_once不仅意味着代码仅会被运行一次,而且还是线程安全的,这就意味着你不需要使用诸如@synchronized之类的来防止使用多个线程或者队列时不同步的问题。
如果被多个线程调用,该函数会同步等等直至代码块完成。
3、实例
+ (AccountManager *)sharedManager {
static AccountManager *sharedInstance = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
这就意味着你任何时候访问共享实例,需要做的仅是:
AccountManager *accountManager = [AccountManager sharedManager];
就这些,你现在在应用中就有了一个共享的实例,该实例只会被创建一次。
4、总结
优点:
1 线程安全
2 很好满足静态分析器要求
3 和自动引用计数(ARC)兼容
4 仅需要少量代码
缺点:
它仍然需要运行创建一个非共享的实例:
AccountManager *accountManager = [[AccountManager alloc] init];
有些时候你希望有这种行为,但如果正在想要的是仅一个实例被实例化就需要注意这点。
5、宏定义单例
//宏定义单例
// .h
#define SingletonH(class) + (instancetype)shared##class;
// .m
#define SingletonM(class) \
static class *_instance; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
\
return _instance; \
} \
\
+ (instancetype)shared##class \
{ \
if (_instance == nil) { \
_instance = [[class alloc] init]; \
} \
\
return _instance; \
}\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instance; \
}