dispatch_async(dispatch_get_main_queue(),^{})存在的一个坑
0.1642017.06.27 10:19:33字数 228阅读 3444
-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions{// Override point for customization after application launch.NSLog(@"before main queue : %@",[NSThread currentThread]);dispatch_async(dispatch_get_main_queue(),^{NSLog(@"main queue");});NSLog(@"after main queue : %@",[NSThread currentThread]);returnYES;}2017-06-2709:33:57.001TestMain[1811:19444]before main queue:<NSThread:0x60000006a080>{number=1,name=main}2017-06-2709:33:57.001TestMain[1811:19444]after main queue:<NSThread:0x60000006a080>{number=1,name=main}2017-06-2709:33:57.012TestMain[1811:19444]main queue
可以看到在main thread中,执行顺序并不是和代码顺序一样,
dispatch_async(dispatch_get_main_queue(),^{NSLog(@"main queue");});
最后执行。
如果不注意的话,可能会导致一些问题。
-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions{// Override point for customization after application launch.NSLog(@"before main queue : %@",[NSThread currentThread]);dispatch_async(dispatch_get_main_queue(),^{NSLog(@"main queue");self.label=[UILabel new];});NSLog(@"after main queue : %@",[NSThread currentThread]);NSLog(@"self.label: %@",self.label);returnYES;}before main queue:<NSThread:0x608000070ec0>{number=1,name=main}after main queue:<NSThread:0x608000070ec0>{number=1,name=main}self.label:(null)main queue
解决方法
参考SDWebImage的宏定义,判断一下当前是不是主线程,如果是直接执行,如果不是,异步执行
#ifndef dispatch_main_async_safe #define dispatch_main_async_safe(block)\ if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\ block();\ } else {\ dispatch_async(dispatch_get_main_queue(), block);\ } #endif
将需要顺序的执行的代码放到同一个作用域里面
原因
应该是和runloop有关的,但是具体的解释还没想明白。
dispatch_async(dispatch_get_main_queue(),^{NSLog(@"main queue");self.label=[UILabel new];});
dispatch_async将block提交给了queue然后立即返回,但是block什么时候执行,由queue说了算。然后,就不知道了……
更新
block 什么时候执行由Runloop说了算,不是由queue说了算,实际就是下一个runloop循环会执行,因为runloop在唤醒后会去处理相关的任务
调用信息
void_dispatch_main_queue_callback_4CF(void*ignored DISPATCH_UNUSED){// the main queue cannot be suspended and no-one looks at this bit// so abuse it to avoid dirtying more memoryif(_dispatch_main_q.dq_side_suspend_cnt){return;}_dispatch_main_q.dq_side_suspend_cnt=true;_dispatch_main_queue_drain(&_dispatch_main_q);_dispatch_main_q.dq_side_suspend_cnt=false;}
网友评论