- (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中,執(zhí)行順序并不是和代碼順序一樣,
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"main queue");
});
最后執(zhí)行。
如果不注意的話,可能會(huì)導(dǎo)致一些問題。
- (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的宏定義,判斷一下當(dāng)前是不是主線程,如果是直接執(zhí)行,如果不是,異步執(zhí)行
#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
- 將需要順序的執(zhí)行的代碼放到同一個(gè)作用域里面
原因
應(yīng)該是和runloop有關(guān)的,但是具體的解釋還沒想明白。
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"main queue");
self.label = [UILabel new];
});
dispatch_async將block提交給了queue然后立即返回,但是block什么時(shí)候執(zhí)行,由queue說了算。然后,就不知道了……
更新
block 什么時(shí)候執(zhí)行由Runloop說了算,不是由queue說了算,實(shí)際就是下一個(gè)runloop循環(huán)會(huì)執(zhí)行,因?yàn)閞unloop在喚醒后會(huì)去處理相關(guān)的任務(wù)
調(diào)用信息
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;
}