单例模式顾名思义,就是一个类一般只会同时存在一个实例,常见的实现方式为在类中编写名为sharedInstance
的类方法。例如:
+(id)sharedImstance{
static EOCClass *sharedlnstance = nil;
@synchronized(self){
if (!sharedlnstance) {
sharedlnstance = [[self alloc] init];
}
}
return sharedlnstance;
}
该方法只会返回全类共用的单例实例,而不会在每次调用时都创建新的实例。
为保证线程安全,上述代码将创建单例实例的代码包裹在同步块里。
GCD中的一个函数可以更简单的执行这种只需执行一次的代码。为:
void dispatch_once (dispatch_once_t *token,
dispatch_block_t block);
此函数接受类型为的dispatch_once_t
的特殊参数token
,此外还接受块参数,在块里面执行我们所需要运行一次的代码。对于给定的token
来说,该函数保证相关的块必定会执行,且仅执行一次。首次调用该函数时,必然会执行块中的代码,最重要的一点在于,此操作完全是线程安全的。请注意,对于只需执行一次的块来说,每次凋用函数时传入的标记都必须完全相同。因此,开发 者通常将标记变量声明在static
或global
作用域里。
将上面的代码改为dispatch_once
来执行,就可以换为:
+ (id)sharedInstance {
static EOCClass ^sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedlnstance = [[self alloc] initJ;
});
return sharedInstance;
}
使用dispatch_once
可以简化代码并且彻底保证线程安全,开发者根本无须担心加锁或同步。所有问题都由GCD
在底层处理。
相比于同步机制的繁琐,dispatch_once
更高效,此函数采用“原子访问”(atomic access)来査询token
,以判断其所对应的代码原来是否已经执行过。速度一般是同步机制的两倍。
要点
- 经常需要编写“只需执行一次的线程安全代码”(thread-safe single-code execution)。通过GCD所提供的
dispatch_once
函数,很容易就能实现此功能。 - 标记应该声明在
static
或global
作用域中,这样的话,在把只需执行一次的块传给dispatch once
函数时,传进去的标记也是相同的。