分享:ios多个网络请求之间的并行与串行场景的处理

ReyZhang
移动开发领域新星创作者
2023-02-22 11:32:55
加精

在日常开发中我们总是会和网络打交道,从服务端拿数据渲染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");
          });
      }];
  }

 

...全文
成就一亿技术人!
拼手气红包 5.00元
597 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

421

社区成员

发帖
与我相关
我的任务
社区描述
专注移动ios平台的软件开发,多年的一线研发经验,实战经验丰富,只为你呈现有价值的信息。
iosflutterandroid 技术论坛(原bbs) 山东省·青岛市
社区管理员
  • ReyZhang
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧