方式一:GCD (最常用)
使用GCD又有2種方式:異步回到主線程和同步回到主線程。2種方式的差別在於是否會阻塞原來的線程。
見下方的代碼和日誌
異步回到主線程(建議使用)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 需要在主線程執行的代碼
});
深入瞭解:
原來線程和主線程並行
執行,即:系統會來回切換這2個線程,看起來像2個線程同時在執行
NSLog(@"開啓一個異步線程");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"正在執行子線程中的代碼");
sleep(1);
NSLog(@"準備回到主線程");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"開始執行main線程中的代碼");
sleep(1);
NSLog(@"繼續執行main線程中的代碼");
sleep(1);
NSLog(@"繼續執行main線程中的代碼");
sleep(1);
NSLog(@"繼續執行main線程中的代碼");
NSLog(@"main線程中的代碼執行完畢");
});
NSLog(@"繼續執行子線程中的代碼");
sleep(1);
NSLog(@"繼續執行子線程中的代碼");
sleep(1);
NSLog(@"繼續執行子線程中的代碼");
sleep(1);
NSLog(@"繼續執行子線程中的代碼");
sleep(1);
NSLog(@"子線程中代碼執行完成");
});
NSLog(@"完成");
2018-12-01 18:44:06.065959+0800 TestApp[4013:192606] 開啓一個異步線程
2018-12-01 18:44:06.066561+0800 TestApp[4013:192606] 完成
2018-12-01 18:44:06.066609+0800 TestApp[4013:192685] 正在執行子線程中的代碼
2018-12-01 18:44:07.072672+0800 TestApp[4013:192685] 準備回到主線程
2018-12-01 18:44:07.073054+0800 TestApp[4013:192685] 繼續執行子線程中的代碼
2018-12-01 18:44:07.073087+0800 TestApp[4013:192606] 開始執行main線程中的代碼
2018-12-01 18:44:08.074562+0800 TestApp[4013:192685] 繼續執行子線程中的代碼
2018-12-01 18:44:08.074564+0800 TestApp[4013:192606] 繼續執行main線程中的代碼
2018-12-01 18:44:09.076120+0800 TestApp[4013:192606] 繼續執行main線程中的代碼
2018-12-01 18:44:09.078331+0800 TestApp[4013:192685] 繼續執行子線程中的代碼
2018-12-01 18:44:10.077170+0800 TestApp[4013:192606] 繼續執行main線程中的代碼
2018-12-01 18:44:10.077491+0800 TestApp[4013:192606] main線程中的代碼執行完畢
2018-12-01 18:44:10.078793+0800 TestApp[4013:192685] 繼續執行子線程中的代碼
2018-12-01 18:44:11.084351+0800 TestApp[4013:192685] 子線程中代碼執行完成
同步回到主線程
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 需要在主線程執行的代碼
});
深入瞭解
原來線程和主線程 串行
執行,即:中斷正在執行的子線程,先回到主線程把需要執行的代碼執行完後,再重新回到子線程繼續執行。
NSLog(@"開啓一個異步線程");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"正在執行子線程中的代碼");
sleep(1);
NSLog(@"準備回到主線程");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"開始執行main線程中的代碼");
sleep(1);
NSLog(@"繼續執行main線程中的代碼");
sleep(1);
NSLog(@"繼續執行main線程中的代碼");
sleep(1);
NSLog(@"繼續執行main線程中的代碼");
NSLog(@"main線程中的代碼執行完畢");
});
NSLog(@"繼續執行子線程中的代碼");
sleep(1);
NSLog(@"繼續執行子線程中的代碼");
sleep(1);
NSLog(@"繼續執行子線程中的代碼");
sleep(1);
NSLog(@"繼續執行子線程中的代碼");
sleep(1);
NSLog(@"子線程中代碼執行完成");
});
NSLog(@"完成");
2018-12-01 18:51:14.045142+0800 TestApp[4146:198711] 開啓一個異步線程
2018-12-01 18:51:14.048935+0800 TestApp[4146:198711] 完成
2018-12-01 18:51:14.048965+0800 TestApp[4146:199189] 正在執行子線程中的代碼
2018-12-01 18:51:15.055313+0800 TestApp[4146:199189] 準備回到主線程
2018-12-01 18:51:15.055767+0800 TestApp[4146:198711] 開始執行main線程中的代碼
2018-12-01 18:51:16.057238+0800 TestApp[4146:198711] 繼續執行main線程中的代碼
2018-12-01 18:51:17.058822+0800 TestApp[4146:198711] 繼續執行main線程中的代碼
2018-12-01 18:51:18.059647+0800 TestApp[4146:198711] 繼續執行main線程中的代碼
2018-12-01 18:51:18.059980+0800 TestApp[4146:198711] main線程中的代碼執行完畢
2018-12-01 18:51:18.060323+0800 TestApp[4146:199189] 繼續執行子線程中的代碼
2018-12-01 18:51:19.060857+0800 TestApp[4146:199189] 繼續執行子線程中的代碼
2018-12-01 18:51:20.066423+0800 TestApp[4146:199189] 繼續執行子線程中的代碼
2018-12-01 18:51:21.071962+0800 TestApp[4146:199189] 繼續執行子線程中的代碼
2018-12-01 18:51:22.077000+0800 TestApp[4146:199189] 子線程中代碼執行完成
方式二:NSOperationQueue
//這種方式等同於 GCD 方式中的異步回到主線程方式
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//需要在主線程執行的代碼
}];
方式三:performSelectorOnMainThread
withObject
: 用來傳遞需要傳會主線程的的參數waitUntilDone
:NO
等價於GCD方式的異步回到主線程,YES
等價於GCD方式中的同步回到主線程
[self performSelectorOnMainThread:@selector(WantToGoBackMianThread:) withObject:@"1" waitUntilDone:YES];
- (void)WantToGoBackMianThread:(id)object{
//需要在主線程執行的代碼
NSLog(@"object:%@",object);
}