分享:ios多个网络请求之间的并行与串行场景的处理
在日常开发中我们总是会和网络打交道,从服务端拿数据渲染UI、上传数据到服务器、登陆等,那么就会遇到一些问题。eg:当用户登陆完毕后才获取数据渲染UI或者是多个网络请求从服务端拿到多个数据后,才进行下一步的操作,那么对网络请求之间顺序的控制是十分重要的,本文对这两种情况进行总结,如有不足之处,请多多指教。同时本文只提供了部分截图,其他运行效果可自行尝试。
原文:https://juejin.cn/post/7078892935093157902
情景一:多个网络请求执行(无序)完后,在执行其他操作
示例代码中用到的宏定义:
#define GlobalQueue dispatch_get_global_queue(0, 0)
#define MainQueue dispatch_get_main_queue()
1.队列组group + notify
思路:group其实就是管理指定queue中任务的。在这里通过调用dispatch_group_notify方法,等待group中管理queue的任务执行完毕后,会在该group指定的队列中执行block内部的代码。
- (void)multipleRequest_NoOrder_after_executeOtherTask_byGroupNotify {
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, GlobalQueue, ^{
sleep(1);
NSLog(@"网络请求1");
});
dispatch_group_async(group, GlobalQueue, ^{
sleep(1);
NSLog(@"网络请求2");
});
dispatch_group_async(group, GlobalQueue, ^{
sleep(1);
NSLog(@"网络请求3");
});
dispatch_group_async(group, GlobalQueue, ^{
sleep(1);
NSLog(@"网络请求4");
});
//当group中的任务执行完后,会调用
dispatch_group_notify(group, MainQueue, ^{
NSLog(@"更新UI");
});
}
运行截图: 第一次运行:

第二次运行:

2. NSOperation + NSOperationQueue
思路:通过NSBlockOperation创建多个任务,将任务添加到NSBlockOperationQueue中.通过调用addBarrierBlock方法,会等到将任务添加到NSBlockOperationQueue中所有的任务执行完毕后,才会执行block中的代码。
- (void)multipleRequest_NoOrder_after_executeOtherTask_byOperation {
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"网络请求1");
}];
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"网络请求2");
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"网络请求3");
}];
NSBlockOperation *block4 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"网络请求4");
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//设置最大并发数
queue.maxConcurrentOperationCount = [NSProcessInfo processInfo].activeProcessorCount;
//waitUntilFinished:是否等待queue中的任务执行完后,才执行后面的代码。会阻塞当前线程
[queue addOperations:@[block1,block2,block3,block4] waitUntilFinished:NO];
//当queue中的所有任务执行完后,会调用
[queue addBarrierBlock:^{
NSLog(@"更新UI");
}];
}
3. 栅栏函数barrier
思路:栅栏函数其实和NSOperationQueue的addBarrierBlock方法相似,都是等待队列中的任务执行完毕后,才执行block中的代码。但是需要注意提到的坑点。
- (void)multipleRequest_NoOrder_after_executeOtherTask_byBarrier {
dispatch_queue_t queue = dispatch_queue_create("ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"网络请求1");
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"网络请求2");
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"网络请求3");
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"网络请求4");
});
//坑点:不能用全局并发队列,栅栏函数会失效并且栅栏函数只能用于自定义创建的并发队列,如果传递dispatch_get_global_queue(0, 0),那么dispatch_barrier_async等价于dispatch_async
dispatch_barrier_async(queue, ^{
NSLog(@"更新UI");
});
}
情景二:多个网络请求执行(有序)完后,在执行其他操作 (线程同步方案)
1. 队列组group + enter + leave
思路:很简单,enter代表一个block任务进入,leave代表一个block任务离开。
- (void)multipleRequest_InOrder_after_executeOtherTask_byGroup {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self request:@"1" finished:^{
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[self request:@"2" finished:^{
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[self request:@"3" finished:^{
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[self request:@"4" finished:^{
dispatch_group_leave(group);
}];
dispatch_group_notify(group, MainQueue, ^{
NSLog(@"更新UI");
});
}
- (void)request:(NSString *)parama finished:(void(^)(void))finished {
dispatch_async(GlobalQueue, ^{
NSLog(@"网络请求%@",parama);
if(finished) { finished(); }
});
}
2. 通过异步+串行队列
原理:异步开启子线程,但是由于是串行队列,任务的执行按照FIFO的原则,那么先进入队列的网络请求任务,会被子线程优先从队列中取出来执行。最终在网络请求4完成后,在主线程刷新UI。
- (void)multipleRequest_InOrder_after_executeOtherTask_byAsyncSerialQueue{
dispatch_queue_t asyncSerialQueue = dispatch_queue_create("AsyncSerialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(asyncSerialQueue, ^{
sleep(1);
NSLog(@"网络请求1");
});
dispatch_async(asyncSerialQueue, ^{
sleep(1);
NSLog(@"网络请求2");
});
dispatch_async(asyncSerialQueue, ^{
sleep(1);
NSLog(@"网络请求3");
});
dispatch_async(asyncSerialQueue, ^{
sleep(1);
NSLog(@"网络请求4");
dispatch_async(MainQueue, ^{
NSLog(@"更新UI");
});
});
运行截图:

3.NSOperation + NSOperationQueue(添加任务之间的依赖关系)
- (void)multipleRequest_InOrder_after_executeOtherTask_byOperation {
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"网络请求1");
}];
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"网络请求2");
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"网络请求3");
}];
NSBlockOperation *block4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"网络请求4");
sleep(1);
}];
[block4 addDependency:block3];
[block3 addDependency:block2];
[block2 addDependency:block1];
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue addOperations:@[block1,block2,block3,block4] waitUntilFinished:NO];
//会等到queue中的任务执行完后才会调用
[operationQueue addBarrierBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"刷新UI");
});
}];
}
相关推荐
iOS判断网络请求超时的方法
本篇文章主要介绍了iOS判断网络请求超时的方法,现在分享给大家,也给大家做个参考。感兴趣的小伙伴们可以参考一下。
iOS微信分享多张图片
iOS多图分享,欢迎关注http://blog.csdn.net/u014220518
swift-iOS原生SDK实现三方登陆与分享
利用QQ、微信的原生SDK实现的三方登陆、分享功能。包括:QQ登陆、微信登陆、微信文本、图片、链接等分享到会话、朋友圈、收藏;QQ文本、图片分享等实用功能
iOS网络层架构设计分享
前些天帮公司做了网络层的重构,当时就想做好了就分享给大家,后来接着做了新版本的需求,现在才有时间整理一下。之前的网络层使用的是直接拖拽导入项目的方式导入了AF,然后还修改了大量的源码,时隔2年,AF已经更新换代很多次了,导致整个重构迁移非常的麻烦。不过看着前辈写的代码,肯定也是一个高人,许多思路和我的一样,但是实现方式又不同,给我很好的参考。在做网络层架构的时候也参考了Casa大神的架构思想,但是还是有所不同。本文没有太多的理论,没有太多的专业术语,一来是方便大家阅读,二来我的基础也没那么好,没有太多华丽的词汇,对于架构来说主要是思路,有思路在,具体的实现就没有问题了。1.网络接口规范2.多服
iOS 新浪微博分享
对于新浪微博分享,里面有详细的文档介绍


