本篇筆記主要針對(duì)的場(chǎng)景問(wèn)題:需要并發(fā)執(zhí)行多個(gè)AFNetworking請(qǐng)求损同,并且在多個(gè)請(qǐng)求成功返回結(jié)果之后咽笼,根據(jù)它們的結(jié)果來(lái)執(zhí)行下一個(gè)任務(wù)凛膏。
一 dispatch_group 介紹
1.1 基本概念:將追加到隊(duì)列的一系列任務(wù)放進(jìn)組中嗡午,可用于監(jiān)聽(tīng)任務(wù)完成情況抚吠。
1.2 常用方法:
- dispatch_group_create() 創(chuàng)建一個(gè)調(diào)度任務(wù)組。
- disaptch_group_async (dispatch_group_t,dispatch_queue_t,block) 將一個(gè)追加到隊(duì)列的任務(wù)提交到任務(wù)組中斥黑。
- dispatch_group_enter/dispatch_group_leave 揖盘, 跟dispath_group_async類似,可理解為手動(dòng)管理任務(wù)添加進(jìn)組和任務(wù)離開(kāi)組锌奴。
- dispatch_group_notify 用來(lái)監(jiān)聽(tīng)組中的任務(wù)全部執(zhí)行完畢兽狭。
- dispatch_group_wait (dispatch_group_t ,dispatch_time_t) 設(shè)置的等待時(shí)間,等待時(shí)間內(nèi)所在的線程停止向下執(zhí)行鹿蜀,時(shí)間結(jié)束后箕慧,如果組中的任務(wù)執(zhí)行完畢,則返回0茴恰,如果沒(méi)有只執(zhí)行完畢則返回非0销钝。
- 通常時(shí)間設(shè)置為dispatch_time_forever,永久等待,此時(shí)當(dāng)組中的任務(wù)全部執(zhí)行完畢后琐簇,wait方法就會(huì)返回蒸健。
二 實(shí)際使用場(chǎng)景(并發(fā)執(zhí)行第多個(gè)任務(wù))
2.1 并發(fā)執(zhí)行非異步任務(wù)
需求描述:并發(fā)執(zhí)行任務(wù)1和任務(wù)2座享,當(dāng)它們執(zhí)行結(jié)束后,執(zhí)行任務(wù)3似忧。
分析:使用dispatch_group_async搭配dispatch_group_notify即可實(shí)現(xiàn)并行執(zhí)行任務(wù)1和任務(wù)2 渣叛,并且監(jiān)聽(tīng)兩個(gè)任務(wù)執(zhí)行完畢之后,再執(zhí)行任務(wù)3盯捌。
2.1.1 代碼解析
- (void)asyncWithGroup {
//創(chuàng)建group
dispatch_group_t group = dispatch_group_create();
//全局并行隊(duì)列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, globalQueue, ^{
NSLog(@"執(zhí)行任務(wù)--1--");
sleep(1);
NSLog(@"執(zhí)行結(jié)束--1--");
});
dispatch_group_async(group, globalQueue, ^{
NSLog(@"執(zhí)行任務(wù)--2--");
sleep(3);
NSLog(@"執(zhí)行結(jié)束--2--");
});
//監(jiān)聽(tīng)組中任務(wù)全部執(zhí)行完畢
dispatch_group_notify(group, globalQueue, ^{
NSLog(@"開(kāi)始執(zhí)行任務(wù)--3--");
});
}
打印情況如下:
可見(jiàn)任務(wù)1和任務(wù)2是并發(fā)執(zhí)行淳衙,并且在他們執(zhí)行完畢之后,才執(zhí)行任務(wù)3饺著。
2.2 并發(fā)執(zhí)行異步任務(wù)
需求描述:并行執(zhí)行任務(wù)1和任務(wù)2箫攀,任務(wù)1和任務(wù)2這里都是使用AFNnetworking發(fā)送請(qǐng)求,等待任務(wù)1和任務(wù)2請(qǐng)求完成(成功或失斢姿ァ)之后靴跛,再繼續(xù)執(zhí)行任務(wù)3。
分析:
- 對(duì)于AFNetworking的請(qǐng)求渡嚣,難點(diǎn)在于是不知道何時(shí)返回結(jié)果梢睛。如果使用dispatch_group_async的話,那么在afn請(qǐng)求調(diào)用之后识椰,該任務(wù)即認(rèn)定結(jié)束了(示例看下面的注意部分)绝葡。
- 那么此時(shí)有兩種實(shí)現(xiàn)方法可以解決這個(gè)問(wèn)題。
- 使用dispatch_group_enter/leave 來(lái)手動(dòng)管理group中任務(wù)執(zhí)行是否結(jié)束腹鹉。
- dispatch_group_async可理解為自動(dòng)管理任務(wù)的進(jìn)組和離開(kāi)組藏畅。
- 使用group搭配dispatch_semaphore信號(hào)量來(lái)解決。
- 使用dispatch_group_enter/leave 來(lái)手動(dòng)管理group中任務(wù)執(zhí)行是否結(jié)束腹鹉。
2.2.1 代碼解析(這里主要針對(duì)第一種實(shí)現(xiàn)方法做說(shuō)明)
//請(qǐng)求連接
static NSString *url = @"http://httpbin.org/get";
/**
封裝afn請(qǐng)求
@param url 使用定義的url
@param result 用于簡(jiǎn)化功咒,將success和failure統(tǒng)一描述
*/
- (void)loadDataWithURL:(NSString *)url result:(void(^)(BOOL isSuccess))result {
__block BOOL isSuccess = NO;
[self.manager GET:url parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
isSuccess = YES;
result(isSuccess);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
isSuccess = NO;
result(isSuccess);
}];
}
/**
使用group并發(fā)執(zhí)行兩個(gè)網(wǎng)絡(luò)請(qǐng)求任務(wù)愉阎,三個(gè)任務(wù)執(zhí)行完之后執(zhí)行任務(wù)3
*/
- (void)loadDataConcurrentWithGroup {
//創(chuàng)建group
dispatch_group_t group = dispatch_group_create();
//全局并發(fā)隊(duì)列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(group);
dispatch_async(globalQueue, ^{
NSLog(@"任務(wù)--1--開(kāi)始");
[self loadDataWithURL:url result:^(BOOL isSuccess) {
NSLog(@"任務(wù)--1--完成");
dispatch_group_leave(group);
}];
});
dispatch_group_enter(group);
dispatch_async(globalQueue, ^{
NSLog(@"任務(wù)--2--開(kāi)始");
[self loadDataWithURL:url result:^(BOOL isSuccess) {
NSLog(@"任務(wù)--2--完成");
dispatch_group_leave(group);
}];
});
dispatch_group_notify(group, globalQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"開(kāi)始執(zhí)行任務(wù)--3--");
});
});
}
打印結(jié)果如下圖所示:
可見(jiàn)任務(wù)1和任務(wù)2是并發(fā)執(zhí)行,等到任務(wù)1和任務(wù)2請(qǐng)求成功返回請(qǐng)求結(jié)果后航瞭,才執(zhí)行任務(wù)3诫硕。
注意:上述代碼如果將dispatch_group_leave(group)放在afn請(qǐng)求外面的話(如下所示)坦辟,會(huì)是什么結(jié)果呢刊侯?
dispatch_async(globalQueue, ^{
NSLog(@"任務(wù)--1--開(kāi)始");
[self loadDataWithURL:url result:^(BOOL isSuccess) {
NSLog(@"任務(wù)--1--完成");
// dispatch_group_leave(group);
}];
dispatch_group_leave(group);
});
此時(shí)在loadDataWithURL調(diào)用之后,發(fā)送afn請(qǐng)求锉走,然后就會(huì)執(zhí)行dispatch_group_leave(group)滨彻,那么此時(shí)其實(shí)跟調(diào)用dispatch_group_async是一樣的意思了。并不能監(jiān)控到兩個(gè)afn請(qǐng)求的成功返回挪蹭。所以運(yùn)行打印結(jié)果如下圖所示:
2.2.2 使用dispatch_group和disaptch_semaphore信號(hào)量實(shí)現(xiàn)方法會(huì)在dispatch_semaphore筆記中介紹亭饵。
結(jié)語(yǔ): 路漫漫其修遠(yuǎn)兮,吾將上下而求索梁厉。