- (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]);
return YES;
}
2017-06-27 09:33:57.001 TestMain[1811:19444] before main queue : <NSThread: 0x60000006a080>{number = 1, name = main}
2017-06-27 09:33:57.001 TestMain[1811:19444] after main queue : <NSThread: 0x60000006a080>{number = 1, name = main}
2017-06-27 09:33:57.012 TestMain[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);
return YES;
}
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 memory
if (_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;
}