dispatch_async(dispatch_get_main_queue(),^{})存在的一個坑
0.1642017.06.27 10:19:33字?jǐn)?shù) 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中屯蹦,執(zhí)行順序并不是和代碼順序一樣,
dispatch_async(dispatch_get_main_queue(),^{NSLog(@"main queue");});
最后執(zhí)行绳姨。
如果不注意的話,可能會導(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);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的宏定義,判斷一下當(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í)行的代碼放到同一個作用域里面
原因
應(yīng)該是和runloop有關(guān)的廓旬,但是具體的解釋還沒想明白。
dispatch_async(dispatch_get_main_queue(),^{NSLog(@"main queue");self.label=[UILabel new];});
dispatch_async將block提交給了queue然后立即返回孕豹,但是block什么時候執(zhí)行,由queue說了算励背。然后,就不知道了……
更新
block 什么時候執(zhí)行由Runloop說了算址儒,不是由queue說了算衅疙,實際就是下一個runloop循環(huán)會執(zhí)行莲趣,因為runloop在喚醒后會去處理相關(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 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;}