GCD的詳解
iOS多線程--徹底學會多線程之『GCD』
GCD線程之間的通訊
一般在主線程里面刷新UI
- 點擊、滾動、拖拽等事件
把耗時操作放在其他線程 - 圖片下載、文件上傳等耗時操作
有時,在其他線程完成了耗時操作時,需要回到主線程,那么就用到了線程之間的通訊。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1------%@",[NSThread currentThread]);
}
// 回到主線程
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"2-------%@",[NSThread currentThread]);
});
});
輸出結果:
2016-09-03 19:34:59.165 GCD[11728:1913039] 1------<NSThread: 0x7f8319c06820>{number = 2, name = (null)}
2016-09-03 19:34:59.166 GCD[11728:1913039] 1------<NSThread: 0x7f8319c06820>{number = 2, name = (null)}
2016-09-03 19:34:59.166 GCD[11728:1912961] 2-------<NSThread: 0x7f8319e00560>{number = 1, name = main}
- 可以看到在其他線程中先執行操作,執行完了之后回到主線程執行主線程相應的操作。
GCD的柵欄方法dispatch_barrier_async
- 我們有時候需要異步執行兩組操作,而且第一組操作執行完之后,才能開始執行第二組操作。這樣我們就需要一個相當于柵欄一樣的一個方法將兩組異步執行的操作組給分割起來,當然這里的操作組里可以包含一個或多個任務。這就需要用到
dispatch_barrier_async
方法在兩個操作組間形成柵欄。
dispatch_queue_t queue = dispatch_queue_create("123456", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"----1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2----%@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"----barrier----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----3----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4----%@",[NSThread currentThread]);
});
輸出結果:
2016-09-03 19:35:51.271 GCD[11750:1914724] ----1-----<NSThread: 0x7fb1826047b0>{number = 2, name = (null)}
2016-09-03 19:35:51.272 GCD[11750:1914722] ----2-----<NSThread: 0x7fb182423fd0>{number = 3, name = (null)}
2016-09-03 19:35:51.272 GCD[11750:1914722] ----barrier-----<NSThread: 0x7fb182423fd0>{number = 3, name = (null)}
2016-09-03 19:35:51.273 GCD[11750:1914722] ----3-----<NSThread: 0x7fb182423fd0>{number = 3, name = (null)}
2016-09-03 19:35:51.273 GCD[11750:1914724] ----4-----<NSThread: 0x7fb1826047b0>{number = 2, name = (null)}
- 可以看出在執行完柵欄前面的操作之后,才執行柵欄操作,最后再執行柵欄后面的操作。
GCD的延時執行方法dispatch_after
- 當我們需要延遲執行一段代碼時,就需要用到GCD的
dispatch_after
方法。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后異步執行這里的代碼
NSLog(@"run----");
});
GCD的一次性代碼(只執行一次)dispatch_once
- 我們在創建單例、或者有整個程序運行過程中只執行一次的代碼的時候,我們就用到了GCD的
dispatch_once
方法。使用dispatch_once
函數能保證某段代碼在程序運行過程中只被執行1次。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只執行一次的代碼(這里默認是線程安全的)
});
GCD的快速迭代方法dispatch_apply
- 通常我們會使用for循環遍歷,但是GCD給我們提供了快速迭代的方法
dispatch_apply
,使我們可以同時遍歷。比如說遍歷0~5這6個數字,for循環的做法是每次取出一個元素,逐個遍歷。dispatch_apply
可以同時遍歷多個數字。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(6, queue, ^(size_t index) {
NSLog(@"%zd----%@",index,[NSThread currentThread]);
});
輸出結果:
2016-09-03 19:37:02.250 GCD[11764:1915764] 1------<NSThread: 0x7fac9a7029e0>{number = 1, name = main}
2016-09-03 19:37:02.250 GCD[11764:1915885] 0------<NSThread: 0x7fac9a614bd0>{number = 2, name = (null)}
2016-09-03 19:37:02.250 GCD[11764:1915886] 2------<NSThread: 0x7fac9a542b20>{number = 3, name = (null)}
2016-09-03 19:37:02.251 GCD[11764:1915764] 4------<NSThread: 0x7fac9a7029e0>{number = 1, name = main}
2016-09-03 19:37:02.250 GCD[11764:1915884] 3------<NSThread: 0x7fac9a76ca10>{number = 4, name = (null)}
2016-09-03 19:37:02.251 GCD[11764:1915885] 5------<NSThread: 0x7fac9a614bd0>{number = 2, name = (null)}
GCD的隊列組dispatch_group
- 有時候我們需要分別異步執行兩個耗時操作,然后當兩個耗時操作都執行完畢后再回到主線程執行操作。這時候我們可以用到GCD的隊列組。
- 我們可以先把任務放到隊列中,然后將隊列放入隊列組中。
- 調用隊列組的
dispatch_group_notify
回到主線程執行操作。
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執行一個耗時操作的異步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執行一個耗時操作的異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等待前面的異步操作都執行完畢后,回到主線程
});