在实际开发过程中经常会有在一个页面有多个网络请求,页面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
。网络耗时的操作才执行。然后就………………错了。