IOS---多个网络请求如何控制回调顺序以及所有网络请求执行完后执行下一步

开发需求:

1、原型是多个网络请求不做任何处理

2、多个网络请求,需要所有网络请求都完成后才能进行下一步的操作。如下载多个图片,下载完了才能展示。

3、多个网络请求,在2情况下还要求所有的网络请求必须回调也按顺序回调。

 

 

实测

首先在viewDidLoad创建一个按钮  点击的时候做网络请求

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1.无处理
    UIButton *Btn = [UIButton buttonWithType:UIButtonTypeCustom];
    Btn.frame = CGRectMake(100, 100, 100, 40);
    Btn.backgroundColor = [UIColor grayColor];
    [Btn setTitle:@"testBtn" forState:UIControlStateNormal];
    [Btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:Btn];
    
}

1、多个网络请求不做任何处理

-(void)btnClick{
    NSString *str = @"https://blog.csdn.net/qq_33226881";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    for (int i=0; i<10; i++) {
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
            NSLog(@"%d---%d",i,i);
            
        }];
        
        [task resume];
    }
    
    NSLog(@"end");
}

运行,控制台输出:

2019-02-21 16:30:53.107132+0800 demo_test[79076:6322778] end
2019-02-21 16:30:53.932530+0800 demo_test[79076:6325473] 6---6
2019-02-21 16:30:53.932687+0800 demo_test[79076:6325484] 7---7
2019-02-21 16:30:53.934681+0800 demo_test[79076:6325484] 8---8
2019-02-21 16:30:53.935822+0800 demo_test[79076:6325484] 0---0
2019-02-21 16:30:53.936317+0800 demo_test[79076:6325562] 2---2
2019-02-21 16:30:53.936517+0800 demo_test[79076:6325562] 9---9
2019-02-21 16:30:53.937033+0800 demo_test[79076:6325562] 5---5
2019-02-21 16:30:53.937587+0800 demo_test[79076:6325556] 4---4
2019-02-21 16:30:53.938096+0800 demo_test[79076:6325556] 1---1
2019-02-21 16:30:53.938598+0800 demo_test[79076:6325562] 3---3

很明显,无任何处理情况下,end最先被打印出来,由于网络请求的异步回调,然后各个网络请求的回调顺序是无序的。

 

2、多个网络请求,需要所有网络请求都完成后才能进行下一步的操作。

(1)使用GCD的dispatch_group_t

-(void)btnClick{
    NSString *str = @"https://blog.csdn.net/qq_33226881";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    dispatch_group_t downloadGroup = dispatch_group_create();
    for (int i=0; i<10; i++) {
        dispatch_group_enter(downloadGroup);
        
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
            NSLog(@"%d---%d",i,i);
            dispatch_group_leave(downloadGroup);
            
        }];
        
        [task resume];
    }
    
    dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
}

运行,控制台输出:

2019-02-21 16:46:40.643445+0800 demo_test[79245:6369355] 6---6
2019-02-21 16:46:40.643764+0800 demo_test[79245:6369362] 7---7
2019-02-21 16:46:40.643868+0800 demo_test[79245:6369315] 8---8
2019-02-21 16:46:40.683800+0800 demo_test[79245:6369356] 9---9
2019-02-21 16:46:40.687189+0800 demo_test[79245:6369315] 2---2
2019-02-21 16:46:40.723518+0800 demo_test[79245:6369315] 4---4
2019-02-21 16:46:40.728108+0800 demo_test[79245:6368107] 1---1
2019-02-21 16:46:40.728782+0800 demo_test[79245:6368107] 5---5
2019-02-21 16:46:40.738189+0800 demo_test[79245:6369356] 3---3
2019-02-21 16:46:40.774204+0800 demo_test[79245:6369362] 0---0
2019-02-21 16:46:40.774317+0800 demo_test[79245:6367926] end

可以看出,end是在所有网络请求之后才输出出来,这也是符合了我们的需求。

 

代码中我们只添加了四行代码

dispatch_group_t downloadGroup = dispatch_group_create();
dispatch_group_enter(downloadGroup);
dispatch_group_leave(downloadGroup);
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
    });

对以上4行代码可理解为:创建一个dispatch_group_t, 每次网络请求前先dispatch_group_enter,请求回调后再dispatch_group_leave,对于enter和leave必须配合使用,有几次enter就要有几次leave,否则group会一直存在。当所有enter的block都leave后,会执行dispatch_group_notify的block。

 

(2)使用GCD的信号量dispatch_semaphore_t

-(void)btnClick{
    NSString *str = @"https://blog.csdn.net/qq_33226881";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    __weak typeof(self) weakSelf = self;
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    for (int i=0; i<10; i++) {
        
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
            NSLog(@"%d---%d",i,i);
            weakSelf.count++;
            if (weakSelf.count==10) {
                dispatch_semaphore_signal(sem);
                weakSelf.count = 0;
            }
            
        }];
        
        [task resume];
    }
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
}

运行,控制台输出:

2019-02-21 17:19:44.727240+0800 demo_test[79572:6438103] 6---6
2019-02-21 17:19:44.727483+0800 demo_test[79572:6438103] 7---7
2019-02-21 17:19:44.727572+0800 demo_test[79572:6438103] 8---8
2019-02-21 17:19:44.769205+0800 demo_test[79572:6438053] 9---9
2019-02-21 17:19:44.770698+0800 demo_test[79572:6438098] 4---4
2019-02-21 17:19:44.771508+0800 demo_test[79572:6438103] 1---1
2019-02-21 17:19:44.812112+0800 demo_test[79572:6438098] 2---2
2019-02-21 17:19:44.812919+0800 demo_test[79572:6434100] 5---5
2019-02-21 17:19:44.813794+0800 demo_test[79572:6438098] 3---3
2019-02-21 17:19:44.854245+0800 demo_test[79572:6438053] 0---0
2019-02-21 17:19:44.854978+0800 demo_test[79572:6433948] end

从输出可以看出,这样的方法也是满足我们的需求的,在这个方法中,我们使用了

dispatch_semaphore_t sem = dispatch_semaphore_create(0);
dispatch_semaphore_signal(sem);
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

对这三句代码可以这样理解:dispatch_semaphore信号量为基于计数器的一种多线程同步机制。如果semaphore计数大于等于1,计数-1,返回,程序继续运行。如果计数为0,则等待。dispatch_semaphore_signal(semaphore)为计数+1操作,dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)为设置等待时间,这里设置的等待时间是一直等待。

对于以上代码通俗一点就是,开始为0,等待,等10个网络请求都完成了,dispatch_semaphore_signal(semaphore)为计数+1,然后计数-1返回,程序继续执行。 (这里也就是为什么有个count变量的原因,记录网络回调的次数,回调10次之后再发信号量,使后面程序继续运行)。

 

3、多个网络请求,在2情况下还要求所有的网络请求必须回调也按顺序回调。

(1)还是使用信号量semaphore完成需求

-(void)btnClick{
    NSString *str = @"https://blog.csdn.net/qq_33226881";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    for (int i=0; i<10; i++) {
        
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
            NSLog(@"%d---%d",i,i);
            dispatch_semaphore_signal(sem);
        }];
        
        [task resume];
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
}

运行,控制台输出:

2019-02-21 17:29:15.208386+0800 demo_test[79679:6474505] 0---0
2019-02-21 17:29:15.307529+0800 demo_test[79679:6474505] 1---1
2019-02-21 17:29:15.378151+0800 demo_test[79679:6474557] 2---2
2019-02-21 17:29:15.447956+0800 demo_test[79679:6474505] 3---3
2019-02-21 17:29:15.554771+0800 demo_test[79679:6474557] 4---4
2019-02-21 17:29:15.639260+0800 demo_test[79679:6474505] 5---5
2019-02-21 17:29:15.713266+0800 demo_test[79679:6474557] 6---6
2019-02-21 17:29:15.796437+0800 demo_test[79679:6470017] 7---7
2019-02-21 17:29:15.878718+0800 demo_test[79679:6474557] 8---8
2019-02-21 17:29:15.965581+0800 demo_test[79679:6474505] 9---9
2019-02-21 17:29:15.966260+0800 demo_test[79679:6469469] end

但这样做一个问题,我们使用这种方式,可以明显感觉出整个过程需要花费的时间大大增加了,不像我们 2(2) 中同时(几乎)开启任务等待完成回调,这里是一个网络请求发出,等待,完成后发出第二个网络请求,等待,完成后再发出第三个,这样我们等待的时间是10个网络请求每一个回调时间的和,在时间上大大增加了消耗,而且对于dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER),它是会阻塞线程的,我们如果需要在网络请求完成后修改UI,那这种方式会影响我们的界面交互,接下来我们对比一下两者时间消耗:

2(2)
2019-02-21 17:19:44.727240+0800 demo_test[79572:6438103] 6---6
2019-02-21 17:19:44.727483+0800 demo_test[79572:6438103] 7---7
2019-02-21 17:19:44.727572+0800 demo_test[79572:6438103] 8---8
2019-02-21 17:19:44.769205+0800 demo_test[79572:6438053] 9---9
2019-02-21 17:19:44.770698+0800 demo_test[79572:6438098] 4---4
2019-02-21 17:19:44.771508+0800 demo_test[79572:6438103] 1---1
2019-02-21 17:19:44.812112+0800 demo_test[79572:6438098] 2---2
2019-02-21 17:19:44.812919+0800 demo_test[79572:6434100] 5---5
2019-02-21 17:19:44.813794+0800 demo_test[79572:6438098] 3---3
2019-02-21 17:19:44.854245+0800 demo_test[79572:6438053] 0---0
2019-02-21 17:19:44.854978+0800 demo_test[79572:6433948] end



3(1)
2019-02-21 17:29:15.208386+0800 demo_test[79679:6474505] 0---0
2019-02-21 17:29:15.307529+0800 demo_test[79679:6474505] 1---1
2019-02-21 17:29:15.378151+0800 demo_test[79679:6474557] 2---2
2019-02-21 17:29:15.447956+0800 demo_test[79679:6474505] 3---3
2019-02-21 17:29:15.554771+0800 demo_test[79679:6474557] 4---4
2019-02-21 17:29:15.639260+0800 demo_test[79679:6474505] 5---5
2019-02-21 17:29:15.713266+0800 demo_test[79679:6474557] 6---6
2019-02-21 17:29:15.796437+0800 demo_test[79679:6470017] 7---7
2019-02-21 17:29:15.878718+0800 demo_test[79679:6474557] 8---8
2019-02-21 17:29:15.965581+0800 demo_test[79679:6474505] 9---9
2019-02-21 17:29:15.966260+0800 demo_test[79679:6469469] end

看得出2(2)花费时间为44.854 - 44.727约100多ms
--- ---3(1)花费时间为15.966 - 15.208约700多ms

 

3(2)用NSConditionLock条件锁(重点推荐)

-(void)btnClick{
    NSString *str = @"https://blog.csdn.net/qq_33226881";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    self.lock = [[NSConditionLock alloc] initWithCondition:0];
    dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i=0; i<10; i++) {
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            dispatch_async(queue, ^{
                [self.lock lockWhenCondition:i];
                NSLog(@"%d---%d",i,i);
                [self.lock unlockWithCondition:i+1];
            });
        }];
        [task resume];
    }
}

运行,控制台输出:

2019-02-21 17:39:27.852553+0800 demo_test[79807:6515122] 0---0
2019-02-21 17:39:27.852737+0800 demo_test[79807:6515128] 1---1
2019-02-21 17:39:27.893596+0800 demo_test[79807:6515129] 2---2
2019-02-21 17:39:27.895559+0800 demo_test[79807:6515128] 3---3
2019-02-21 17:39:27.895696+0800 demo_test[79807:6515122] 4---4
2019-02-21 17:39:27.895843+0800 demo_test[79807:6514898] 5---5
2019-02-21 17:39:27.895913+0800 demo_test[79807:6514899] 6---6
2019-02-21 17:39:27.895984+0800 demo_test[79807:6514901] 7---7
2019-02-21 17:39:27.896057+0800 demo_test[79807:6514900] 8---8
2019-02-21 17:39:27.896157+0800 demo_test[79807:6515121] 9---9

可以看出所用时间还不到100ms,在这个方法中,我们使用了

//初始化一个NSConditionLock对象,锁条件为0
self.lock = [[NSConditionLock alloc] initWithCondition:0];
//当i满足锁条件时加锁
[self.lock lockWhenCondition:i];
//解锁,并重置锁的条件为i+1
[self.lock unlockWithCondition:i+1];

添加代码理解:

1、初始化了一个锁,并添加锁条件为0

2、当i满足锁条件的时候就进行加锁

3、进行解锁,并重置锁的条件为i+1

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
uni-app是一个跨平台的开发框架,可以同时开发iOS、Android和Web应用。在uni-app中,可以使用uni.request方法进行网络请求。 uni.request方法是封装了原生的XMLHttpRequest和fetch方法,可以发送HTTP请求并获取响应数据。它支持GET、POST等常见的请求方式,并且可以设置请求头、请求参数等。 使用uni.request方法发送网络请求的基本步骤如下: 1. 引入uni.request方法:在需要发送网络请求的页面或组件中,使用import语句引入uni.request方法。 2. 调用uni.request方法:使用uni.request方法发送网络请求,传入请求的URL、请求参数、请求头等信息。 3. 处理响应数据:在uni.request方法的回调函数中,可以获取到服务器返回的响应数据,并进行相应的处理。 以下是一个示例代码,演示了如何使用uni.request方法发送GET请求: ``` import uniRequest from '@/common/request.js'; uniRequest({ url: 'https://api.example.com/users', method: 'GET', success: (res) => { console.log(res.data); }, fail: (err) => { console.log(err); } }); ``` 在上述代码中,我们首先引入了一个名为uniRequest的封装方法,该方法封装了uni.request方法。然后,我们调用uniRequest方法发送了一个GET请求,并在成功回调函数中打印了服务器返回的数据。 需要注意的是,uni.request方法是异步的,所以我们需要通过回调函数来处理响应数据。在回调函数中,可以根据服务器返回的状态码、响应数据等进行相应的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值