使用dispatch_queue_set_specific,避免使用dispatch_get_current_queue——笔记

《Effective Objective-C 2.0  编写高质量iOS与OS X代码的52个有效方法》(第四十六条:不要使用dispatch_get_current_queue)笔记

要点如下:

1、dispatch_get_current_queue():返回的是执行当前代码的队列

测试代码如下:

- (void)test{
    dispatch_queue_t queueA = dispatch_queue_create("queueA", NULL);
    dispatch_queue_t queueB = dispatch_queue_create("queueB", NULL);
    TPLog(@"A======%@, B=====%@",queueA, queueB);
    dispatch_sync(queueA, ^{
        TPLog(@"A-------%@", dispatch_get_current_queue());
        dispatch_sync(queueB, ^{
            TPLog(@"B-------%@", dispatch_get_current_queue());
            //do something
        });
    });
}

打印结果如下:

2019-02-22 11:28:31.700979+0800 TPWeiShangTool[13994:640633] A======<OS_dispatch_queue_serial: queueA>, B=====<OS_dispatch_queue_serial: queueB>
2019-02-22 11:28:31.701152+0800 TPWeiShangTool[13994:640633] A-------<OS_dispatch_queue_serial: queueA>
2019-02-22 11:28:42.965341+0800 TPWeiShangTool[13994:640633] B-------<OS_dispatch_queue_serial: queueB>

上述测试代码,如果在queueB队列中do something的位置调用dispatch_sync(queueA, ...);就会造成死锁,而使用dispatch_get_current_queue却无法通过判断当前队列来避免。故引出"队列特有数据"

2、dispatch_queue_set_specific:队列特有数据,可以把任意数据以键值对的形式关联到队列中。

void dispatch_queue_set_specific(
    dispatch_queue_t queue, //待设置标记的队列
    const void *key, //标记的键
    void *context, //标记的值。注意,这里键和值是指针,即地址,故context中可以放任何数据,但必须手动管理context的内存
    dispatch_function_t destructor //析构函数,但所在队列内存被回收,或者context值改变时,会被调用
);

通过键值对,就可以判断当前执行的任务是否包含在某个队列中,因为系统会根据给定的键,沿着队列的层级体系(即父队列)进行查找键所对应的值,如果到根队列还没找到,就说明当前任务不包含在你要判断的队列中,进而可以避免(1)中描述的死锁问题

简单理解就是:给某个队列加个标记,找到这个标记就说明包含在这个队列中

示例代码:

dispatch_queue_t queueA = dispatch_queue_create("queueA", NULL);
dispatch_queue_t queueB = dispatch_queue_create("queueB", NULL);
dispatch_set_target_queue(queueB, queueA);

static int kQueueSpecific;
CFStringRef queueSpecificValue = CGSTR("queueA"); 
//这里使用CoreFoundation字符串,是因为ARC不会自动管理CoreFoundation对象的内存,dispatch_queue_set_specific的第三个参数(值)需要手动管理内存

dispatch_queue_set_specific(
    queueA, 
    &kQueueSpecific, 
    (void *)queueSpecificValue,  //需要手动管理内存
    (dispatch_function_t)CFRelease //用CFRelease清理旧值
); //给queueA队列做标记

dispatch_sync(queueB, ^{
    dispatch_block_t block = ^{ NSLog("No deadlock!"); };
    CFStringRef retrievedValue = dispatch_get_specific(&kQueueSpecific); //根据键获取值
    if(retrievedValue){ //根据键找到了值,就说明包含在queueA目标队列中
        block();
    }else{ //没有包含在queueA中
        dispatch_sync(queueA, block);
    }
})

比如UI刷新必须要回到主线程里执行,就可以考虑使用这种方式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值