如何处理多个并发的网络请求之间的依赖关系?
有a,b,c,d四个网络请求,如何判断a,b,c,d都执行完毕了?如何让a,b,c,d顺序执行?
之前在网上看到最多的答案就是使用dispatch_group,具体方案是这样:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_ DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ /*任务 a */ }); dispatch_group_async(group, queue, ^{ /*任务 b */ }); dispatch_group_async(group, queue, ^{ /* 任务c */ }); dispatch_group_async(group, queue, ^{ /* 任务d */ }); dispatch_group_notify(group,dispatch_get_main_queue(), ^{ // 在a、b、c、d异步执行完成后,会回调到这里 });
但是我自己实际实践了之后,发现并不是这样。我的需求场景是这样,我需要下载四张图片,四张图片都下载完成后合成一张图片。我是使用基于AFN封装的网络请求工具类请求下载图片的,只有当请求有回调的时候(不管成功或失败),才能代表这次网络请求执行完毕。而使用上面的方法只能保证网络请求执行了,但并没有回调完成。下面直接上代码说明:
- (void)testGCDAPI { dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NetWorkBase *netWorkManager = [NetWorkBase new]; dispatch_group_async(group, queue, ^{ NSLog(@"start1"); [netWorkManager startGet:IMAGE_TEST_1 parameters:nil withBlock:^(id result, BOOL succ) { NSLog(@"回调1"); _imageView1.image = [UIImage imageWithData:result]; }]; }); dispatch_group_async(group, queue, ^{ NSLog(@"start2"); [netWorkManager startGet:IMAGE_TEST_2 parameters:nil withBlock:^(id result, BOOL succ) { NSLog(@"回调2"); _imageView2.image = [UIImage imageWithData:result]; }]; }); dispatch_group_async(group, queue, ^{ NSLog(@"start3"); [netWorkManager startGet:IMAGE_TEST_3 parameters:nil withBlock:^(id result, BOOL succ) { NSLog(@"回调3"); _imageView3.image = [UIImage imageWithData:result]; }]; }); dispatch_group_async(group, queue, ^{ NSLog(@"start4"); [netWorkManager startGet:IMAGE_TEST_4 parameters:nil withBlock:^(id result, BOOL succ) { NSLog(@"回调4"); _imageView4.image = [UIImage imageWithData:result]; }]; }); dispatch_group_notify(group, queue, ^{ NSLog(@"4张图片全都加载完毕"); }); }
控制台打印效果如下:
可以看出,以上方法并不能保证group_notify里的代码是在网络请求有回调之后再执行。那么如何才能保证group_notify在所有网络请求都有回调之后才调用呢?
我们可以使用变量flag来标识网络请求回调,但是这样不够优雅,也不是使用GCD来实现了。
- (void)testGCDAPI { dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_get_main_queue(); NetWorkBase *netWorkManager = [NetWorkBase new]; dispatch_group_enter(group); [netWorkManager startGet:IMAGE_TEST_1 parameters:nil withBlock:^(id result, BOOL succ) { NSLog(@"回调1"); _imageView1.image = [UIImage imageWithData:result]; dispatch_group_leave(group); }]; dispatch_group_enter(group); [netWorkManager startGet:IMAGE_TEST_2 parameters:nil withBlock:^(id result, BOOL succ) { NSLog(@"回调2"); _imageView2.image = [UIImage imageWithData:result]; dispatch_group_leave(group); }]; dispatch_group_enter(group); [netWorkManager startGet:IMAGE_TEST_3 parameters:nil withBlock:^(id result, BOOL succ) { NSLog(@"回调3"); _imageView3.image = [UIImage imageWithData:result]; dispatch_group_leave(group); }]; dispatch_group_enter(group); [netWorkManager startGet:IMAGE_TEST_4 parameters:nil withBlock:^(id result, BOOL succ) { NSLog(@"回调4"); _imageView4.image = [UIImage imageWithData:result]; dispatch_group_leave(group); }]; dispatch_group_notify(group, queue, ^{ NSLog(@"4张图片全都加载完毕"); }); }
在每个网络请求开始前使用dispatch_group_enter来进行标识,网络请求有回调后使用dispatch_group_leave来进行标识,这样就能保证group_notify在所有网络请求都有回调之后才调用。而同时也保证了这四个网络请求是顺序执行的
控制台打印效果: