dispatch_group實踐,AFN3.0多個網絡請求
在實際開發過程中經常會有在一個頁面有多個網絡請求,頁面UI需要在所有網絡請求全部回來的情況下更新。先簡單看一個具體的問題:
頁面有三個網絡請求a、b、c。三個網絡請求都成功的情況下刷新UI,有一個失敗就認爲請求失敗,不進行UI刷新。
目前想到的方法
- 添加
標識
進行判斷是否所有的網絡請求都是成功的 - 通過
信號量
判斷 - 直接使用
dispatch_group
(當然也可以結合信號量
)
這裏就簡單使用dispatch_group
來實踐一下:
先簡單瞭解一下必須的東西
常用方法
1、
dispatch_group_create
創建一個調度任務組2、
dispatch_group_async
把一個任務異步提交到任務組裏3、
dispatch_group_enter/dispatch_group_leave
這種方式用在不使用dispatch_group_async來提交任務,且必須配合使用4、
dispatch_group_notify
用來監聽任務組事件的執行完畢5、
dispatch_group_wait
設置等待時間
實現一個dispatch_group_async
簡單的例子
基本需求和文章前面的需求差不多,task 1
、task 2
、task 3
、task 4
四個任務,task 4
要在task 1
、task 2
、task 3
執行完成之後在執行。
先看一下代碼:
- (void)testDisGroup {
dispatch_queue_t demoQuene = dispatch_queue_create("demoQuene", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
NSLog(@"\n\nmain thread %@\n\n",[NSThread currentThread]);
dispatch_group_async(group, demoQuene, ^{
sleep(arc4random_uniform(5));
NSLog(@"task 1 %@",[NSThread currentThread]);
});
dispatch_group_async(group, demoQuene, ^{
sleep(arc4random_uniform(5));
NSLog(@"task 2 %@",[NSThread currentThread]);
});
dispatch_group_async(group, demoQuene, ^{
sleep(arc4random_uniform(5));
NSLog(@"task 3 %@",[NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"task 4 %@",[NSThread currentThread]);
});
}
看一下結果:
當然task 1
、task 2
、task 3
完成的順序不是固定,最後是task 4
,需要看系統怎麼分配資源。
升級一下dispatch_group_async
的例子
在上面任務的基礎上添加一個需求,就是task 2
、task 3
要有一個順序,比如task 2
要在task 3
執行完成之後才能執行。
看一下代碼(當然實現的方案很多,這只是個例子):
- (void)testDisGroup {
dispatch_queue_t demoQueneCONCURRENT = dispatch_queue_create("demoQuene", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t demoQueneSERIAL = dispatch_queue_create("demoQuene", DISPATCH_QUEUE_SERIAL);
dispatch_group_t group = dispatch_group_create();
NSLog(@"\n\nmain thread %@\n\n",[NSThread currentThread]);
dispatch_group_async(group, demoQueneCONCURRENT, ^{
sleep(arc4random_uniform(5));
NSLog(@"task 1 %@",[NSThread currentThread]);
});
dispatch_group_async(group, demoQueneSERIAL, ^{
sleep(arc4random_uniform(5));
NSLog(@"task 3 %@",[NSThread currentThread]);
});
dispatch_group_async(group, demoQueneSERIAL, ^{
sleep(arc4random_uniform(5));
NSLog(@"task 2 %@",[NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"task 4 %@",[NSThread currentThread]);
});
}
執行結果:
另一個結果:
當然這個結果也存在多種情況,不變的是task 4
要在task 1
、task 2
、task 3
執行完成之後在執行,task 2
要在task 3
執行完成之後才能執行。其他的順序是不確定的。
使用dispatch_group_enter/dispatch_group_leave
複寫一下第一個例子
-(void)testDisGroupEnterAndLeave {
dispatch_queue_t demoQueneCONCURRENT = dispatch_queue_create("demoQuene2", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(demoQueneCONCURRENT, ^{
NSLog(@"task 1 %@",[NSThread currentThread]);
sleep(arc4random_uniform(5));
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(demoQueneCONCURRENT, ^{
NSLog(@"task 2 %@",[NSThread currentThread]);
sleep(arc4random_uniform(5));
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(demoQueneCONCURRENT, ^{
NSLog(@"task 3 %@",[NSThread currentThread]);
sleep(arc4random_uniform(5));
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"task 4 %@",[NSThread currentThread]);
sleep(arc4random_uniform(5));
});
}
運行結果:
另一結果:
使用dispatch_group_enter/dispatch_group_leave
複寫一下第二個例子
上代碼:
-(void)testDisGroupEnterAndLeave {
dispatch_queue_t demoQueneCONCURRENT = dispatch_queue_create("demoQuene2", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t demoQueneSERIAL = dispatch_queue_create("demoQuene3", DISPATCH_QUEUE_SERIAL);
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(demoQueneCONCURRENT, ^{
NSLog(@"task 1 %@",[NSThread currentThread]);
sleep(arc4random_uniform(5));
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(demoQueneSERIAL, ^{
NSLog(@"task 3 %@",[NSThread currentThread]);
sleep(arc4random_uniform(5));
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(demoQueneSERIAL, ^{
NSLog(@"task 2 %@",[NSThread currentThread]);
sleep(arc4random_uniform(5));
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"task 4 %@ \n\n\n.",[NSThread currentThread]);
sleep(arc4random_uniform(5));
});
}
結果(兩次結果寫在一起了):
開始實戰
還是文章開始的那道題現在看一下
頁面有三個網絡請求a、b、c。三個網絡請求都成功的情況下刷新UI,有一個失敗就認爲請求失敗,不進行UI刷新。
@interface TestThread () {
dispatch_group_t _group;
}
@end
@implementation TestThread
- (void)p_loadBannerData {
dispatch_group_enter(_group);
AdvBannerApi *bannerApi = [[AdvBannerApi alloc] initWithAdvType:AdvTypeBanner];
[bannerApi startWithSuccessBlock:^(ApiResult * _Nullable result) {
NSLog(@"task 1 success");
dispatch_group_leave(_group);
} failureBlock:^(NSError * _Nullable error) {
NSLog(@"task 1 failure");
dispatch_group_leave(_group);
}];
}
- (void)p_loadCourseListData {
dispatch_group_enter(_group);
QualityCourseApi *courseApi = [[QualityCourseApi alloc] initWithStart:@"0"
count:@"20"];
[courseApi startWithSuccessBlock:^(ApiResult * _Nullable result) {
NSLog(@"task 2 success");
dispatch_group_leave(_group);
} failureBlock:^(NSError * _Nullable error) {
NSLog(@"task 2 failure");
dispatch_group_leave(_group);
}];
}
- (void)p_loadLivingLessonData {
dispatch_group_enter(_group);
LessonForecastApi *api = [[LessonForecastApi alloc] init];
[api startWithSuccessBlock:^(ApiResult * _Nullable result) {
NSLog(@"task 3 success");
dispatch_group_leave(_group);
} failureBlock:^(NSError * _Nullable error) {
NSLog(@"task 3 failure");
dispatch_group_leave(_group);
}];
}
- (void)reloadUI {
NSLog(@"task 4");
}
-(void)disGroupEnterAndLeave {
_group = dispatch_group_create();
[self p_loadBannerData];
[self p_loadCourseListData];
[self p_loadLivingLessonData];
dispatch_group_notify(_group, dispatch_get_main_queue(), ^{
NSLog(@"run task 4 %@",[NSThread currentThread]);
[self reloadUI];
});
}
@end
看一下結果:
其他的寫法就一一實現了。現在看一下錯誤的寫法
@interface TestThread () {
dispatch_group_t _group;
}
@end
@implementation TestThread
- (void)p_loadBannerData {
AdvBannerApi *bannerApi = [[AdvBannerApi alloc] initWithAdvType:AdvTypeBanner];
[bannerApi startWithSuccessBlock:^(ApiResult * _Nullable result) {
NSLog(@"task 1 success");
} failureBlock:^(NSError * _Nullable error) {
NSLog(@"task 1 failure");
}];
}
- (void)p_loadCourseListData {
QualityCourseApi *courseApi = [[QualityCourseApi alloc] initWithStart:@"0"
count:@"20"];
[courseApi startWithSuccessBlock:^(ApiResult * _Nullable result) {
NSLog(@"task 2 success");
} failureBlock:^(NSError * _Nullable error) {
NSLog(@"task 2 failure");
}];
}
- (void)p_loadLivingLessonData {
LessonForecastApi *api = [[LessonForecastApi alloc] init];
[api startWithSuccessBlock:^(ApiResult * _Nullable result) {
NSLog(@"task 3 success");
} failureBlock:^(NSError * _Nullable error) {
NSLog(@"task 3 failure");
}];
}
- (void)reloadUI {
NSLog(@"task 4");
}
-(void)disGroup {
dispatch_queue_t demoQueneCONCURRENT = dispatch_queue_create("demoQuene", DISPATCH_QUEUE_CONCURRENT);
_group = dispatch_group_create();
dispatch_group_async(_group, demoQueneCONCURRENT, ^{
[self p_loadBannerData];
});
dispatch_group_async(_group, demoQueneCONCURRENT, ^{
[self p_loadCourseListData];
});
dispatch_group_async(_group, demoQueneCONCURRENT, ^{
[self p_loadLivingLessonData];
});
dispatch_group_notify(_group, dispatch_get_main_queue(), ^{
NSLog(@"run task 4 %@",[NSThread currentThread]);
[self reloadUI];
});
}
@end
看一下結果:
很顯然結果是錯誤的,
task 4
最先得出了結果,主要因爲
dispatch_group_async(_group, demoQueneCONCURRENT, ^{
});
開啓了一個新線程,然後
[self p_loadBannerData];
網絡請求又開啓了一個線程。
dispatch_group_async(_group, demoQueneCONCURRENT, ^{
});
開啓的3個新線程執行完之後執行task 4
。網絡耗時的操作才執行。然後就………………錯了。