iOS技术

dispatch_once_t详解

2021-08-24  本文已影响0人  野码道人

概览

typedef intptr_t dispatch_once_t;

定义在once.h中,整个api很少,实现直接内联在头文件,如下

void
dispatch_once(dispatch_once_t *predicate,
        DISPATCH_NOESCAPE dispatch_block_t block);
void
_dispatch_once(dispatch_once_t *predicate,
        DISPATCH_NOESCAPE dispatch_block_t block)
{
    if (DISPATCH_EXPECT(*predicate, ~0l) != ~0l) {
        dispatch_once(predicate, block);
    } else {
        dispatch_compiler_barrier();
    }
    DISPATCH_COMPILER_CAN_ASSUME(*predicate == ~0l);
}
#undef dispatch_once
#define dispatch_once _dispatch_once
#endif
#endif // DISPATCH_ONCE_INLINE_FASTPATH

如上就是我们常用的dispatch_once,通过block实现,我们调用的dispatch_once实际上调用的是_dispatch_once函数

void
dispatch_once_f(dispatch_once_t *predicate, void *_Nullable context,
        dispatch_function_t function);
void
_dispatch_once_f(dispatch_once_t *predicate, void *_Nullable context,
        dispatch_function_t function)
{
    if (DISPATCH_EXPECT(*predicate, ~0l) != ~0l) {
        dispatch_once_f(predicate, context, function);
    } else {
        dispatch_compiler_barrier();
    }
    DISPATCH_COMPILER_CAN_ASSUME(*predicate == ~0l);
}
#undef dispatch_once_f
#define dispatch_once_f _dispatch_once_f
#endif // DISPATCH_ONCE_INLINE_FASTPATH

如上是通过c函数指针实现,我们调用的dispatch_once_f实际上调用的是_dispatch_once_f函数

使用场景

像这样,写一个单例

+ (instancetype)sharedInstance {
    static Person *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

或者像这样,控制页面对象生命周期只触发一次的操作

@property (nonatomic, assign) dispatch_once_t onceToken;

dispatch_once(&_onceToken, ^{
    // do something
});

原理

+ (instancetype)sharedInstance {
    static Person *sharedInstance = nil;
    static dispatch_once_t onceToken;
    NSLog(@"%li", onceToken);
    dispatch_once(&onceToken, ^{
        NSLog(@"%li", onceToken);
        sharedInstance = [[self alloc] init];
        NSLog(@"%li", onceToken);
    });
    NSLog(@"%li", onceToken);
    return sharedInstance;
}
打印:
2021-08-23 13:05:47.412501+0800 GCDDemo[4517:2524707] 0
2021-08-23 13:05:47.412585+0800 GCDDemo[4517:2524707] 256
2021-08-23 13:05:47.412621+0800 GCDDemo[4517:2524707] 256
2021-08-23 13:05:47.412647+0800 GCDDemo[4517:2524707] -1

两个static关键字控制变量只初始化一次,存储在静态区,&是因为函数参数定义是dispatch_once_t *predicate指针,取地址操作用作引用传递,dispatch_once用来控制sharedInstance指针只赋值一次

上一篇 下一篇

猜你喜欢

热点阅读