dispatch_once概念解析
dispatch_once 是 Grand Central Dispatch(GCD) 中的一种线程安全的单例创建方式,在 iOS 开发中常被用来创建全局唯一的单例对象。其核心是利用 dispatch_once 函数,确保指定 block 只会被执行一次,并且是线程安全的,也就是说不会存在多个线程同时执行该 block 的情况。
dispatch_once 函数的声明如下:
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
它包含了一个 predicate 参数和一个 block 参数。其中,predicate 是一个指向 dispatch_once_t 结构体的指针,用来判断该 block 是否已经被执行过。block 则是需要执行的单例创建操作。
通常情况下,我们会在 dispatch_once 函数中执行以下两个步骤:
- 调用 dispatch_once 函数时,dispatch_once_t 结构体会被初始化为 0。
- 在 block 中执行单例创建操作,创建成功后将 dispatch_once_t 结构体的值修改为非 0 值。
完成上述两个步骤后,再次调用 dispatch_once 函数时,由于 dispatch_once_t 的值已经被修改为非 0 值,dispatch_once 函数将不会再次执行 block 中的内容,从而确保该单例只会被创建一次。
整个程序运行中只会执行一次,使用dispatch_once可以简化代码并且彻底保证线程安全,开发者根本无须担心加锁或者同步。所有问题都由GCD在底层处理。由于每次调用时都必须使用完全相同的标记,所以标记要声明成static。所以用在单例模式上是最好的
下面是一个使用 dispatch_once 函数创建单例的例子:
+ (instancetype)sharedInstance {
static MySingleton *instance;
static dispatch_once_t dispatchOnceToken;
dispatch_once(&dispatchOnceToken, ^{
instance = [[MySingleton alloc] init];
});
return instance;
}
此代码中,dispatch_once_t 结构体的值将在整个应用程序生命周期内只初始化一次。另外,使用 GCD 的单例创建方式,可以减少线程冲突,提高代码的性能和可读性。
使用场景
dispatch_once一般使用在单例模式上,其要点是整个程序运行中只会执行一次。当然只要是那些只需要执行一次的方法,用dispatch_once最简单最安全。