在iOS開(kāi)發(fā)中我們經(jīng)常會(huì)遇到一起請(qǐng)求多個(gè)網(wǎng)絡(luò)數(shù)據(jù)的情況…但是有些操作卻是要在所有的網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求結(jié)束之后才可以進(jìn)行的….比如說(shuō)刷新控件收回.或者某些UI控件的更新..這種情況就不能單純的在某一條網(wǎng)絡(luò)請(qǐng)求結(jié)束后的block里操作了.一涉及到異步,GCD的強(qiáng)大之處就體現(xiàn)出來(lái)了..先上代碼:
*** 對(duì)列組與信號(hào)量 ***
//信號(hào)量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
//隊(duì)列組
dispatch_group_t group = dispatch_group_create();
//創(chuàng)建隊(duì)列 - 串行隊(duì)列與全局并發(fā)隊(duì)列擇一即可
// 使用串行隊(duì)列進(jìn)行網(wǎng)絡(luò)請(qǐng)求 -- 網(wǎng)絡(luò)請(qǐng)求的開(kāi)始無(wú)序,且在同一線(xiàn)程
dispatch_queue_t queue = dispatch_queue_create("www.baidu.com", DISPATCH_QUEUE_SERIAL);
// 使用并發(fā)隊(duì)列進(jìn)行網(wǎng)絡(luò)請(qǐng)求 -- 網(wǎng)絡(luò)請(qǐng)求的開(kāi)始無(wú)序,且線(xiàn)程不固定
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//任務(wù)一
dispatch_group_async(group, queue, ^{
// 無(wú)論成功或者失敗都要對(duì)信號(hào)量進(jìn)行標(biāo)記
NSLog(@"此次請(qǐng)求線(xiàn)程是111111:%@",[NSThread currentThread]);
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
NSLog(@"success 此次返回的是111111 線(xiàn)程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_semaphore_signal(semaphore);
NSLog(@"failure 此次返回的是111111 線(xiàn)程是:%@",[NSThread currentThread]);
}];
});
//任務(wù)二
dispatch_group_async(group, queue, ^{
NSLog(@"此次請(qǐng)求線(xiàn)程是222222:%@",[NSThread currentThread]);
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
NSLog(@"success 此次返回的是222222 線(xiàn)程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_semaphore_signal(semaphore);
NSLog(@"failure 此次返回的是222222 線(xiàn)程是:%@",[NSThread currentThread]);
}];
});
//任務(wù)三
dispatch_group_async(group, queue, ^{
NSLog(@"此次請(qǐng)求線(xiàn)程是333333:%@",[NSThread currentThread]);
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
NSLog(@"success 此次返回的是333333 線(xiàn)程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// 模擬網(wǎng)絡(luò)延遲
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_semaphore_signal(semaphore);
NSLog(@"failure 此次返回的是333333 線(xiàn)程是:%@",[NSThread currentThread]);
});
}];
});
// 所有網(wǎng)絡(luò)請(qǐng)求結(jié)束后會(huì)來(lái)到這個(gè)方法
dispatch_group_notify(group, queue, ^{
//3個(gè)任務(wù),3個(gè)信號(hào)等待.
// 這里信號(hào)等待需要與實(shí)際任務(wù)數(shù)相同 -- 若此處信號(hào)等待數(shù)量多于任務(wù)數(shù)(其實(shí)是任務(wù)成功或者失敗后標(biāo)記的信號(hào)量總數(shù)) 則后續(xù)代碼永遠(yuǎn)不會(huì)被執(zhí)行,若此處信號(hào)等待數(shù)量少于任務(wù)數(shù),則會(huì)提前執(zhí)行
NSLog(@"當(dāng)前線(xiàn)程是:%@",[NSThread currentThread]);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//這里就是所有異步任務(wù)請(qǐng)求結(jié)束后執(zhí)行的代碼 -- UI操作需要回到主線(xiàn)程
dispatch_async(dispatch_get_main_queue(), ^{
// 刷新UI
NSLog(@"主線(xiàn)程刷新UI 線(xiàn)程是:%@",[NSThread currentThread]);
});
});
** ??在這里為何使用隊(duì)列組之后還要使用信號(hào)量-- 因?yàn)樵谶@里隊(duì)列組只能保證入組的任務(wù)執(zhí)行完畢,但是在入組后的異步操作,并不會(huì)等待,需要使用信號(hào)量等待 **
- 任務(wù)的成功與失敗回調(diào)中都必須標(biāo)記信號(hào)量
dispatch_semaphore_signal(semaphore); - 信號(hào)等待時(shí)間和任務(wù)數(shù)必須一致
- 創(chuàng)建的隊(duì)列類(lèi)型不同會(huì)有稍微區(qū)別,代碼中給出了兩種,可自行選擇
真對(duì)信號(hào)量的情況幾種情況配圖:

隊(duì)列組- 信號(hào)量正常.png

信號(hào)等待量小于任務(wù)數(shù).png

信號(hào)等待量大于任務(wù)數(shù).png
*** 對(duì)列組方法2 ***
dispatch_group_t group = dispatch_group_create();
//創(chuàng)建隊(duì)列 - 串行隊(duì)列與全局并發(fā)隊(duì)列擇一即可
// 使用串行隊(duì)列進(jìn)行網(wǎng)絡(luò)請(qǐng)求 -- 網(wǎng)絡(luò)請(qǐng)求的開(kāi)始無(wú)序,且在同一線(xiàn)程
dispatch_queue_t queue = dispatch_queue_create("www.baidu.com", DISPATCH_QUEUE_SERIAL);
// 使用并發(fā)隊(duì)列進(jìn)行網(wǎng)絡(luò)請(qǐng)求 -- 網(wǎng)絡(luò)請(qǐng)求的開(kāi)始無(wú)序,且線(xiàn)程不固定
// queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"此次請(qǐng)求線(xiàn)程是111111:%@",[NSThread currentThread]);
// 網(wǎng)絡(luò)請(qǐng)求一
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_group_leave(group);
NSLog(@"success 此次返回的是111111 線(xiàn)程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_group_leave(group);
NSLog(@"failure 此次返回的是111111 線(xiàn)程是:%@",[NSThread currentThread]);
}];
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"此次請(qǐng)求線(xiàn)程是222222:%@",[NSThread currentThread]);
// 網(wǎng)絡(luò)請(qǐng)求二
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_group_leave(group);
NSLog(@"success 此次返回的是222222 線(xiàn)程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_group_leave(group);
NSLog(@"failure 此次返回的是222222 線(xiàn)程是:%@",[NSThread currentThread]);
}];
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"此次請(qǐng)求線(xiàn)程是333333:%@",[NSThread currentThread]);
// 網(wǎng)絡(luò)請(qǐng)求三
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_group_leave(group);
NSLog(@"success 此次返回的是333333 線(xiàn)程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_group_leave(group);
NSLog(@"failure 此次返回的是333333 線(xiàn)程是:%@",[NSThread currentThread]);
}];
});
// 所有網(wǎng)絡(luò)請(qǐng)求結(jié)束后會(huì)來(lái)到這個(gè)方法
dispatch_group_notify(group, queue, ^{
NSLog(@"所有網(wǎng)絡(luò)請(qǐng)求完畢1 線(xiàn)程是:%@",[NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
// 刷新UI
NSLog(@"主線(xiàn)程刷新UI 線(xiàn)程是:%@",[NSThread currentThread]);
});
});
在隊(duì)列組的使用中,創(chuàng)建的隊(duì)列不同,也會(huì)稍微有些區(qū)別:
- 創(chuàng)建串行隊(duì)列 -- 網(wǎng)絡(luò)請(qǐng)求的開(kāi)始無(wú)序,且在同一線(xiàn)程
- 創(chuàng)建全局并發(fā)隊(duì)列 -- 網(wǎng)絡(luò)請(qǐng)求的開(kāi)始無(wú)序,且線(xiàn)程不固定
- 入組和出組必須和任務(wù)數(shù)相對(duì)應(yīng) -
dispatch_group_enter(group)和dispatch_group_leave(group)如數(shù)量不對(duì)應(yīng)會(huì)崩潰
此處有圖:

隊(duì)列組- 有序隊(duì)列.png

隊(duì)列組 - 全局并發(fā)隊(duì)列.png