group 頭文件中函數(shù)的解析:
/*
OS_OBJECT_DECL(dispatch_object);
#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)
*/
// 從上面可以看出 dispatch_group 是 dispatch_object 子類
DISPATCH_DECL(dispatch_group);
dispatch_group_t == DISPATCH_DECL(dispatch_group);
/*
創(chuàng)建一個(gè)組滩愁, 創(chuàng)建的組可能與 block 相關(guān)聯(lián)。
這個(gè)調(diào)度組能夠被用來(lái)等待他引用的 block 的完成秕磷。
- result : 一個(gè)新的組涵妥。 在失敗的情況下返回 NULL
*/
dispatch_group_t
dispatch_group_create(void);
/**
調(diào)度組 在 queue 異步執(zhí)行 block
*/
void
dispatch_group_async(
dispatch_group_t group, // 調(diào)度組對(duì)象
dispatch_queue_t queue, // 隊(duì)列
dispatch_block_t block // block
);
/**
調(diào)度組 在 queue 異步執(zhí)行 函數(shù)
*/
void
dispatch_group_async_f(
dispatch_group_t group, // 調(diào)度組對(duì)象
dispatch_queue_t queue, // 隊(duì)列
void *context, // 上下文(傳遞給函數(shù)的)
dispatch_function_t work // 函數(shù)
);
long
dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);
// 組中異步執(zhí)行任務(wù)全部執(zhí)行完成的通知
void
dispatch_group_notify(
dispatch_group_t group, // 隊(duì)列組
dispatch_queue_t queue, // 執(zhí)行任務(wù)的隊(duì)列
dispatch_block_t block); // 任務(wù)
// 組中異步執(zhí)行的函數(shù)全部執(zhí)行的通知
void
dispatch_group_notify_f(
dispatch_group_t group, // 隊(duì)列組
dispatch_queue_t queue, // 執(zhí)行任務(wù)的隊(duì)列
void *context, // 上下文
dispatch_function_t work); // 函數(shù)
// 入組函數(shù)
void
dispatch_group_enter(dispatch_group_t group);
// 出組函數(shù)
void
dispatch_group_leave(dispatch_group_t group);
調(diào)度組在項(xiàng)目中的使用(調(diào)度組的基本使用)
調(diào)度組:
調(diào)度組是用來(lái)協(xié)調(diào)一個(gè)或多個(gè)任務(wù)提交到隊(duì)列異步觸發(fā)的。 應(yīng)用程序可以使用調(diào)度組等待所有調(diào)度組中的所有任務(wù)的完成。
所有異步隊(duì)列執(zhí)行完畢后得到一個(gè)通知覆旭。
**場(chǎng)景: **
a 異步下載任務(wù)退子,b 異步下載任務(wù), c 異步下載任務(wù)型将。
只有在 a寂祥, b, c 三個(gè)異步下載任務(wù)全部完成的情況下七兜。才通知主線程刷新界面丸凭。亦可以通知某個(gè)隊(duì)列執(zhí)行其他的操作。
NSLog(@"before: %@", [NSThread currentThread]);
// 創(chuàng)建一個(gè)組 (獲得一個(gè)新的腕铸,空的調(diào)度組)
dispatch_group_t g = dispatch_group_create();
// 將隊(duì)列關(guān)聯(lián)組
dispatch_group_async(g, dispatch_get_global_queue(0, 0), ^{
NSLog(@"taskA: %@", [NSThread currentThread]);
});
// 將隊(duì)列關(guān)聯(lián)組
dispatch_group_async(g, dispatch_get_global_queue(0, 0), ^{
NSLog(@"taskB: %@", [NSThread currentThread]);
});
// 將隊(duì)列關(guān)聯(lián)組
dispatch_group_async(g, dispatch_get_global_queue(0, 0), ^{
NSLog(@"taskC: %@", [NSThread currentThread]);
});
// 組中的隊(duì)列全部執(zhí)行完畢后就通知調(diào)度組
dispatch_group_notify(g, dispatch_get_main_queue(), ^{
NSLog(@"MainTask: %@", [NSThread currentThread]);
});
NSLog(@"after: %@", [NSThread currentThread]);
// 打印結(jié)果
2016-06-23 09:12:05.162 Thread-Objc[9371:984276] before: <NSThread: 0x7f8c437028a0>{number = 1, name = main}
2016-06-23 09:12:05.163 Thread-Objc[9371:984276] after: <NSThread: 0x7f8c437028a0>{number = 1, name = main}
2016-06-23 09:12:05.163 Thread-Objc[9371:984320] taskA: <NSThread: 0x7f8c43712610>{number = 2, name = (null)}
2016-06-23 09:12:05.163 Thread-Objc[9371:984328] taskC: <NSThread: 0x7f8c43500a80>{number = 4, name = (null)}
2016-06-23 09:12:05.163 Thread-Objc[9371:984323] taskB: <NSThread: 0x7f8c4376ada0>{number = 3, name = (null)}
2016-06-23 09:12:05.167 Thread-Objc[9371:984276] MainTask: <NSThread: 0x7f8c437028a0>{number = 1, name = main}
上面的代碼是一個(gè)簡(jiǎn)單的使用方式惜犀。
調(diào)度組的使用的原理解析
打開終端輸入
// 使用這個(gè)命令可以查看 GCD 的詳細(xì)文檔
$ man dispatch
// 查看和 group 相關(guān)的文檔
$ man dispatch_group_create
文檔示例
(官方文檔的說(shuō)明)
// dispatch_group_async() 函數(shù)的操作和下面是等價(jià)的:
The dispatch_group_async() convenience function behaves like so:
void
dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispat
ch_block_t block)
{
// 引用計(jì)數(shù)器加1
dispatch_retain(group);
// 入組
dispatch_group_enter(group);
// 任務(wù)異步執(zhí)行
dispatch_async(queue, ^{
// 執(zhí)行任務(wù)
block();
// 出組(通知組,任務(wù)執(zhí)行完畢)
dispatch_group_leave(group);
// 引用計(jì)數(shù)器減1
dispatch_release(group);
});
}
示例代碼改寫
NSLog(@"before: %@", [NSThread currentThread]);
dispatch_group_t g = dispatch_group_create();
dispatch_group_enter(g);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"taskA: %@", [NSThread currentThread]);
dispatch_group_leave(g);
});
dispatch_group_enter(g);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"taskB: %@", [NSThread currentThread]);
dispatch_group_leave(g);
});
dispatch_group_enter(g);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"taskC: %@", [NSThread currentThread]);
dispatch_group_leave(g);
});
dispatch_group_notify(g, dispatch_get_main_queue(), ^{
NSLog(@"MainTask: %@", [NSThread currentThread]);
});
NSLog(@"after: %@", [NSThread currentThread]);
// 打印結(jié)果
2016-06-23 09:35:52.744 Thread-Objc[9540:1004789] before: <NSThread: 0x7fdec3d04920>{number = 1, name = main}
2016-06-23 09:35:52.744 Thread-Objc[9540:1004789] after: <NSThread: 0x7fdec3d04920>{number = 1, name = main}
2016-06-23 09:35:52.745 Thread-Objc[9540:1004833] taskA: <NSThread: 0x7fdec3d11d30>{number = 2, name = (null)}
2016-06-23 09:35:52.745 Thread-Objc[9540:1004829] taskC: <NSThread: 0x7fdec3c09fa0>{number = 3, name = (null)}
2016-06-23 09:35:52.745 Thread-Objc[9540:1004822] taskB: <NSThread: 0x7fdec3d09a50>{number = 4, name = (null)}
2016-06-23 09:35:52.749 Thread-Objc[9540:1004789] MainTask: <NSThread: 0x7fdec3d04920>{number = 1, name = main}
/*
dispatch_group_enter(g); 操作都在 g 所在線程狠裹。
即當(dāng)前線程虽界, 在進(jìn)行異步操作之前, dispatch_group_enter(g) 都已經(jīng)全部執(zhí)行完畢涛菠。
g 中已經(jīng)完整的記錄了 block 的個(gè)數(shù)莉御。
追蹤 NSLog(@"after: %@", [NSThread currentThread]); 的打印可以知道。
執(zhí)行一次 dispatch_group_enter(g) 操作俗冻,block 在組中的記錄就會(huì) 加 1 颈将。
在子線程中執(zhí)行一次 dispatch_group_leave(g); 會(huì)使 block 在組中的記錄就會(huì) 減 1 。
當(dāng)組中的 block 記錄的值為 0 的時(shí)候言疗,就會(huì)調(diào)用 dispatch_group_notify() 函數(shù)晴圾。
*/
理解上面的實(shí)例后,對(duì)于 GCD 中的組基本的學(xué)習(xí)已經(jīng)差不多了
細(xì)節(jié)知識(shí)點(diǎn)說(shuō)明:
dispatch_group_enter();
和 dispatch_group_leave();
必須成對(duì)使用噪奄。 這兩個(gè)函數(shù)會(huì)更新 block 在組中的數(shù)量死姚。
在這個(gè)示例中除了
dispatch_group_wait
和dispatch_group_async_f
基本都用了一遍。
dispatch_group_async_f
是函數(shù)調(diào)用的基本不用勤篮。
- **dispatch_group_wait :
** 意思是等待 group 中所有的 block 都執(zhí)行完畢觸發(fā)這個(gè)函數(shù)都毒,或者等待指定的時(shí)間完成后觸發(fā)這個(gè)函數(shù)。這個(gè)指定的時(shí)間內(nèi)group 變?yōu)榭张龅蓿@個(gè)函數(shù)將返回一個(gè) 0 账劲,表示成功。否則就是一個(gè)非空的值金抡。當(dāng)參數(shù)的值為DISPATCH_TIME_FOREVER
的時(shí)候瀑焦, 返回值總為空。
注意:- 只有在所有的任務(wù)都添加到隊(duì)列 后 才建議調(diào)用
dispatch_group_wait ()
函數(shù)梗肝,如果后續(xù)還有新的 block 添加到 組中榛瓮,請(qǐng)使用新的組。 ( 這個(gè)dispatch_group_wait () 還是必須在最后調(diào)用) - 只有在所有的任務(wù)都添加到隊(duì)列 后 才建議調(diào)用
dispath_group_notify()
函數(shù)巫击,如果后續(xù)還有新的 block 添加到 組中禀晓,請(qǐng)使用新的組精续。 ( 這個(gè)dispath_group_notify() 還是必須在最后調(diào)用)
- 只有在所有的任務(wù)都添加到隊(duì)列 后 才建議調(diào)用
-
dispatch_group_wait() 和 dispath_group_notify() 的 選擇:
dispatch_group_wait (DISPATCH_TIME_FOREVER) == dispath_group_notify()
AFN 中的網(wǎng)絡(luò)請(qǐng)求超時(shí)就是使用dispatch_group_wait ()
實(shí)現(xiàn)的。 當(dāng)一個(gè)時(shí)間結(jié)束后自動(dòng)返回一個(gè)超時(shí)錯(cuò)誤粹懒。