這篇文章介紹了GCD的使用,如果對(duì)事例輸出結(jié)果有疑惑不是很懂的話,請(qǐng)看這篇文章,會(huì)原理了使用起來就有底氣了。(http://www.reibang.com/p/5840523fb3ea)
1.任務(wù)的創(chuàng)建方法
// 同步執(zhí)行任務(wù)
dispatch_sync(queue1, ^{
NSLog(@"%@", [NSThread currentThread]); // 這里放具體的任務(wù)代碼
});
// 異步執(zhí)行任務(wù)
dispatch_async(queue1, ^{
NSLog(@"%@", [NSThread currentThread]); // 這里放具體的任務(wù)代碼
});
2.隊(duì)列的創(chuàng)建方法
// 串行隊(duì)列的創(chuàng)建方法
dispatch_queue_t queue1 = dispatch_queue_create("test1.queue", DISPATCH_QUEUE_SERIAL);
// 并行隊(duì)列的創(chuàng)建方法
dispatch_queue_t queue2 = dispatch_queue_create("test2.queue", DISPATCH_QUEUE_CONCURRENT);
// 獲取全局并發(fā)隊(duì)列
dispatch_queue_t queue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 獲取主隊(duì)列(如:渲染UI等操作都必須在主隊(duì)列中執(zhí)行)
dispatch_queue_t mainQueue = dispatch_get_main_queue();
- 使用
dispatch_queue_create
創(chuàng)建對(duì)象撮竿,第一個(gè)參數(shù)表示隊(duì)列的唯一標(biāo)識(shí)符,用于debug笔呀,可為空幢踏;第二個(gè)參數(shù)用來指定是串行隊(duì)列還是并發(fā)隊(duì)列。DISPATCH_QUEUE_SERIAL
表示是串行隊(duì)列许师,DISPATCH_QUEUE_CONCURRENT
表示是并發(fā)隊(duì)列房蝉。 - 并發(fā)隊(duì)列還可以使用
dipatch_get_global_queue
來創(chuàng)建全局并發(fā)隊(duì)列。GCD默認(rèn)提供了全局的并發(fā)隊(duì)列微渠,需要傳入兩個(gè)參數(shù)搭幻。第一個(gè)參數(shù)表示隊(duì)列的優(yōu)先級(jí),一般用DISPATCH_QUEUE_PRIORITY_DEFAULT
逞盆。第二個(gè)參數(shù)傳0即可檀蹋。 - 一個(gè)app運(yùn)行都有且只有一個(gè)主隊(duì)列,如界面渲染等操作都是要回到主隊(duì)列去執(zhí)行的云芦。
3.GCD的基本使用方法
1.同步執(zhí)行 + 并發(fā)隊(duì)列
2.同步執(zhí)行 + 串行隊(duì)列
3.同步執(zhí)行 + 主隊(duì)列
4.異步執(zhí)行 + 并發(fā)隊(duì)列(最常用)
5.異步執(zhí)行 + 串行隊(duì)列
6.異步執(zhí)行 + 主隊(duì)列
并發(fā)隊(duì)列 | 串行隊(duì)列 | 主隊(duì)列 | |
---|---|---|---|
同步(sync) | 沒有開啟新線程俯逾,串行執(zhí)行任務(wù) | 沒有開啟新線程,串行執(zhí)行任務(wù) | 沒有開啟新線程焕数,串行執(zhí)行任務(wù) |
異步(async) | 有開啟新線程纱昧,并發(fā)執(zhí)行任務(wù) | 有開啟新線程(1條),串行執(zhí)行任務(wù) | 沒有開啟新線程堡赔,串行執(zhí)行任務(wù) |
1.同步執(zhí)行 + 并發(fā)隊(duì)列
不會(huì)開啟新的線程,執(zhí)行完一個(gè)任務(wù)再執(zhí)行下一個(gè)任務(wù)
// 同步 + 并行
- (void)syncConcurrent
{
NSLog(@"start......");
dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1------%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"2------%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"3------%@",[NSThread currentThread]);
}
});
NSLog(@"end......");
}
對(duì)應(yīng)的輸出:
2016-11-07 20:39:55.815238 GCDTest[62422:2294460] start......
2016-11-07 20:39:55.819010 GCDTest[62422:2294460] 1------<NSThread: 0x100201d90>{number = 1, name = main}
2016-11-07 20:39:55.821131 GCDTest[62422:2294460] 1------<NSThread: 0x100201d90>{number = 1, name = main}
2016-11-07 20:39:55.821686 GCDTest[62422:2294460] 2------<NSThread: 0x100201d90>{number = 1, name = main}
2016-11-07 20:39:55.821716 GCDTest[62422:2294460] 2------<NSThread: 0x100201d90>{number = 1, name = main}
2016-11-07 20:39:55.821739 GCDTest[62422:2294460] 3------<NSThread: 0x100201d90>{number = 1, name = main}
2016-11-07 20:39:55.821760 GCDTest[62422:2294460] 3------<NSThread: 0x100201d90>{number = 1, name = main}
2016-11-07 20:39:55.821776 GCDTest[62422:2294460] end......
從輸出結(jié)果可以看出设联,并沒有創(chuàng)建新的線程善已,雖然是并發(fā)隊(duì)列灼捂,然而依然是在當(dāng)前線程中按順序執(zhí)行。
2. 同步執(zhí)行 + 串行隊(duì)列
不會(huì)開啟新線程换团,在當(dāng)前線程執(zhí)行任務(wù)悉稠。執(zhí)行完一個(gè)任務(wù)再執(zhí)行下一個(gè)任務(wù)。
// 同步 + 串行
- (void)syncSerial
{
NSLog(@"begin.......");
dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1------%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"2------%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"3------%@",[NSThread currentThread]);
}
});
NSLog(@"end.......");
}
對(duì)應(yīng)輸出結(jié)果:
2016-11-07 20:53:40.087101 GCDTest[63292:2342125] begin.......
2016-11-07 20:53:40.088562 GCDTest[63292:2342125] 1------<NSThread: 0x1003009e0>{number = 1, name = main}
2016-11-07 20:53:40.088631 GCDTest[63292:2342125] 1------<NSThread: 0x1003009e0>{number = 1, name = main}
2016-11-07 20:53:40.088670 GCDTest[63292:2342125] 2------<NSThread: 0x1003009e0>{number = 1, name = main}
2016-11-07 20:53:40.088699 GCDTest[63292:2342125] 2------<NSThread: 0x1003009e0>{number = 1, name = main}
2016-11-07 20:53:40.088717 GCDTest[63292:2342125] 3------<NSThread: 0x1003009e0>{number = 1, name = main}
2016-11-07 20:53:40.088732 GCDTest[63292:2342125] 3------<NSThread: 0x1003009e0>{number = 1, name = main}
2016-11-07 20:53:40.088741 GCDTest[63292:2342125] end.......
3. 同步執(zhí)行 + 主隊(duì)列
在主線程中調(diào)用會(huì)出現(xiàn)線程卡死艘包。
// 同步 + 主線程 (這里的syncMain方法假設(shè)是在主線程中執(zhí)行的)
- (void)syncMain
{
NSLog(@"begin.......");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1------%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"2------%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"3------%@",[NSThread currentThread]);
}
});
NSLog(@"end.......");
}
對(duì)應(yīng)的輸出:
2016-11-07 21:00:42.449770 GCDTest[63753:2366743] begin.......
這里出現(xiàn)了線程死鎖的猛,至于為什么出現(xiàn)死鎖,請(qǐng)看這篇文章: http://www.reibang.com/p/5840523fb3ea
4. 異步執(zhí)行 + 并發(fā)隊(duì)列 (常用)
可同時(shí)開啟多線程想虎,任務(wù)交替執(zhí)行
// 異步 + 并發(fā)
- (void)asyncConcurrent
{
NSLog(@"begin.......");
dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1------%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"2------%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"3------%@",[NSThread currentThread]);
}
});
NSLog(@"end.......");
}
輸出結(jié)果:
2016-11-07 21:57:29.792065 GCDTest[67516:2568538] begin.......
2016-11-07 21:57:29.793060 GCDTest[67516:2568538] end.......
2016-11-07 21:57:29.793827 GCDTest[67516:2568759] 1------<NSThread: 0x100300180>{number = 2, name = (null)}
2016-11-07 21:57:29.794795 GCDTest[67516:2568761] 3------<NSThread: 0x100401fb0>{number = 3, name = (null)}
2016-11-07 21:57:29.794928 GCDTest[67516:2568759] 1------<NSThread: 0x100300180>{number = 2, name = (null)}
2016-11-07 21:57:29.795082 GCDTest[67516:2568761] 3------<NSThread: 0x100401fb0>{number = 3, name = (null)}
2016-11-07 21:57:29.796385 GCDTest[67516:2568760] 2------<NSThread: 0x1002052c0>{number = 4, name = (null)}
2016-11-07 21:57:29.796430 GCDTest[67516:2568760] 2------<NSThread: 0x1002052c0>{number = 4, name = (null)}
5. 異步執(zhí)行 + 串行隊(duì)列
會(huì)開啟新線程卦尊,串行隊(duì)列中的任務(wù)會(huì)在新線程中按順序執(zhí)行
// 異步 + 串行
- (void)asyncSerial
{
NSLog(@"begin.......");
dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1------%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"2------%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"3------%@",[NSThread currentThread]);
}
});
NSLog(@"end.......");
}
輸出結(jié)果:
2016-11-07 22:13:45.792144 GCDTest[68539:2627655] begin.......
2016-11-07 22:13:45.793360 GCDTest[68539:2627655] end.......
2016-11-07 22:13:45.794873 GCDTest[68539:2627680] 1------<NSThread: 0x100203c10>{number = 2, name = (null)}
2016-11-07 22:13:45.794943 GCDTest[68539:2627680] 1------<NSThread: 0x100203c10>{number = 2, name = (null)}
2016-11-07 22:13:45.794986 GCDTest[68539:2627680] 2------<NSThread: 0x100203c10>{number = 2, name = (null)}
2016-11-07 22:13:45.795008 GCDTest[68539:2627680] 2------<NSThread: 0x100203c10>{number = 2, name = (null)}
2016-11-07 22:13:45.795031 GCDTest[68539:2627680] 3------<NSThread: 0x100203c10>{number = 2, name = (null)}
2016-11-07 22:13:45.795051 GCDTest[68539:2627680] 3------<NSThread: 0x100203c10>{number = 2, name = (null)}
6. 異步執(zhí)行 + 主隊(duì)列
// 異步 + 主隊(duì)列
- (void)asyncMain
{
NSLog(@"begin.......");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1------%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"2------%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"3------%@",[NSThread currentThread]);
}
});
NSLog(@"end.......");
}
2016-11-07 22:31:36.138 GCDTest[69907:2692640] begin.......
2016-11-07 22:31:36.138 GCDTest[69907:2692640] end.......
2016-11-07 22:31:36.258 GCDTest[69907:2692640] 1------<NSThread: 0x60000007f380>{number = 1, name = main}
2016-11-07 22:31:36.258 GCDTest[69907:2692640] 1------<NSThread: 0x60000007f380>{number = 1, name = main}
2016-11-07 22:31:36.259 GCDTest[69907:2692640] 2------<NSThread: 0x60000007f380>{number = 1, name = main}
2016-11-07 22:31:36.260 GCDTest[69907:2692640] 2------<NSThread: 0x60000007f380>{number = 1, name = main}
2016-11-07 22:31:36.261 GCDTest[69907:2692640] 3------<NSThread: 0x60000007f380>{number = 1, name = main}
2016-11-07 22:31:36.261 GCDTest[69907:2692640] 3------<NSThread: 0x60000007f380>{number = 1, name = main}
4.GCD線程之間的通訊
在iOS開發(fā)過程中,我們通常把一些耗時(shí)的操作放在其他線程舌厨,比如說圖片下載岂却、文件上傳等耗時(shí)操作。而當(dāng)我們有時(shí)候在其他線程完成了耗時(shí)操作時(shí)裙椭,需要回到主線程躏哩,那么就用到了線程之間的通訊。
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]);
});
});
運(yùn)行結(jié)果:
2016-11-07 22:58:40.252 GCDTest[71673:2790911] 1------<NSThread: 0x60000026afc0>{number = 3, name = (null)}
2016-11-07 22:58:40.252 GCDTest[71673:2790911] 1------<NSThread: 0x60000026afc0>{number = 3, name = (null)}
2016-11-07 22:58:40.280 GCDTest[71673:2790802] 2-------<NSThread: 0x60000007dec0>{number = 1, name = main}
5.GCD的隊(duì)列組dispatch_group
有時(shí)候我們會(huì)有這樣的需求:分別異步執(zhí)行2個(gè)耗時(shí)操作揉燃,然后當(dāng)2個(gè)耗時(shí)操作都執(zhí)行完畢后再回到主線程執(zhí)行操作扫尺。這時(shí)候我們可以用到GCD的隊(duì)列組。
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的異步操作都執(zhí)行完畢后炊汤,回到主線程...
});
6.GCD的柵欄方法 dispatch_barrier_async
我們有時(shí)需要異步執(zhí)行兩組操作器联,而且第一組操作執(zhí)行完之后才能開始執(zhí)行第二組操作。這樣我們就需要一個(gè)相當(dāng)于柵欄一樣的方法將兩組異步執(zhí)行的操作分隔婿崭。
- (void)barrier
{
dispatch_queue_t queue = dispatch_queue_create("12312312", 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]);
});
}
輸出結(jié)果:
2016-11-07 23:39:03.902 GCDTest[74313:2937448] ----2-----<NSThread: 0x608000078540>{number = 4, name = (null)}
2016-11-07 23:39:03.902 GCDTest[74313:2937439] ----1-----<NSThread: 0x608000078500>{number = 3, name = (null)}
2016-11-07 23:39:03.902 GCDTest[74313:2937439] ----barrier-----<NSThread: 0x608000078500>{number = 3, name = (null)}
2016-11-07 23:39:03.902 GCDTest[74313:2937439] ----3-----<NSThread: 0x608000078500>{number = 3, name = (null)}
2016-11-07 23:39:03.902 GCDTest[74313:2937448] ----4-----<NSThread: 0x608000078540>{number = 4, name = (null)}
如果沒有dispatch_barrier_async這個(gè)方法拨拓,這4個(gè)任務(wù)執(zhí)行是沒有先后順序的,完全隨機(jī)氓栈,那么加上這個(gè)柵欄方法之后渣磷,會(huì)嚴(yán)格按照先隨機(jī)順序執(zhí)行完柵欄之前的所有任務(wù),然后再執(zhí)行柵欄方法之后的任務(wù)授瘦。
7.GCD的其它方法
-
GCD的延時(shí)執(zhí)行方法
dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后回到主線程執(zhí)行這里的代碼
NSLog(@"111");
});
NSLog(@"222");
這里的after是會(huì)異步延時(shí)2秒的醋界,2秒后回到主線程執(zhí)行代碼塊的內(nèi)容,所以輸出結(jié)果是提完,先輸出222形纺,2秒后再輸出111。
-
GCD只執(zhí)行一次代碼
dispatch_once
我們?cè)趧?chuàng)建單例徒欣、或者有整個(gè)程序運(yùn)行過程中只執(zhí)行一次的代碼時(shí)逐样,我們就用到了GCD的dispatch_once
方法。使用dispatch_once
函數(shù)能保證某段代碼在程序運(yùn)行過程中只被執(zhí)行1次。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
});