单例,顾名思义,即有且只有一个实例。
例如我们用到的NSNotificationCenter、NSFileManager等,其default方法,就是用的单例技术。
那么创建函数(sharedInstance)被多次调用,以及多线程场景下,如何保证这一点?
一、从苹果的一些文档中发现官方给出的方式是:
//在.m中实现如下内容及方法
static MyClass *class = nil; //定义静态全局变量
@implementation MyClass
+(MyClass *)sharedMyClass{
@synchronized(self){ //为了确保多线程情况下,仍然确保实体的唯一性
if (!class) {
[[self alloc] init]; //该方法会调用 allocWithZone
}
}
return class;
}
// 重写alloc,确保使用同一块内存
+(id)allocWithZone:(NSZone *)zone{
@synchronized(self){
if (!class) {
class = [super allocWithZone:zone]; //确保使用同一块内存地址
return class;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone;{
return self; //确保copy对象也是唯一
}
-(id)retain{
return self; //确保计数唯一
}
- (unsigned)retainCount
{
return UINT_MAX; //计数永远为-1
}
- (id)autorelease
{
return self;//确保自动计数唯一
}
- (oneway void)release
{
//重写计数释放方法
}
@end
这种方法真正的确保了使用同一块内存块,确保了object的唯一性。
唯一的缺点是这种方法实现全起来有点麻烦。
二、使用GCD技术:
从引入Grand Central Dispatch (GCD)后, 一般使用GCD中的dispatch_once函数来实现。
函数形式如下:
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
第一个参数predicate,该参数是检查后面第二个参数所代表的代码块是否被调用的谓词,
第二个参数则是在整个应用程序中只会被调用一次的代码块。
dispach_once函数可以保证不管被调用几次,函数中的代码块(block)只会被执行一次,而且还是线程安全的。
+(instancetype)sharedInstance
{
static ClassName* _sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once (&oncePredicate, ^{
_sharedInstance = [[ClassName alloc] init];
});
return _sharedInstance;
}
这里充分利用了static的特性:
static变量只会被初始化一次,之后的函数调用会使用变量上一次的值,而不会重新创建一个。
_sharedInstance和oncePredicate都只有一个。