iOS-请求同步执行

「这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战

前言

网络请求大部分情况下, 大家都是使用异步的方式去请求, 这样不会界面的主线程的卡住的情况发生, 但是在有些特殊的情况下, 是需求同时多个请求去请求, 并且需要这几个请求都返回的时候才能继续后续的操作, 每个请求又都是异步的, 那么该如何处理这种情况呢?

这种情景还是很多的, 我们可以通过过使用 # dispatch_semaphore_t 信号量的方式来让多个请求去执行, 然后等多个请求完成后, 收到信号量的信号来执行下一步操作.

实践

信号量通过是两个函数同时使用的

// 创建一个信号,value:信号量
dispatch_semaphore_create(<#long value#>)

// 使某个信号的信号量+1
dispatch_semaphore_signal(<#dispatch_semaphore_t dsema#>)

// 某个信号进行等待或等待降低信号量 timeout:等待时间,永远等待为 DISPATCH_TIME_FOREVER
dispatch_semaphore_wait(<#dispatch_semaphore_t dsema#>, <#dispatch_time_t timeout#>)
复制代码

dispatch_semaphore_create 使用这个函数来创建一个信号量

dispatch_semaphore_signal 这个函数的作用是使信号量增加1

dispatch_semaphore_wait 这个函数的作用是 等待信号量 阻断下一步的操作, 等信号量降低之后再执行后续操作

实战过程可能是这样的

- (NSDictionary *)request {
    __block NSDictionary *response = @{};
    dispatch_semaphore_t sp = dispatch_semaphore_create(0);
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", nil];
    NSString *url = @"http://www.baidu.com";
    [manager GET:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        response = responseObject;
        dispatch_semaphore_signal(sp);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        dispatch_semaphore_signal(sp);
    }];
    
    dispatch_semaphore_wait(sp, DISPATCH_TIME_FOREVER);
    return response;
}
复制代码

这里是一个示例的请求范例, 但是会发现一个问题, 主线程被卡住, 无法执行.

具体的原因是因为afn在拿到返回的数据时, 会回调到主线程, 而现在主线程已经被阻塞, 从而无法实现所想要功能.

如何解决这个问题? 其实很简单, 将afn的回调放到子线程中就可以解决

- (NSDictionary *)request {
    __block NSDictionary *response = @{};
    dispatch_semaphore_t sp = dispatch_semaphore_create(0);
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", nil];
    
    
    // 给manager一个自己的线程
    manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    
    NSString *url = @"http://www.baidu.com";
    [manager GET:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        response = responseObject;
        dispatch_semaphore_signal(sp);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        dispatch_semaphore_signal(sp);
    }];
    
    dispatch_semaphore_wait(sp, DISPATCH_TIME_FOREVER);
    return response;
}
复制代码

这样就可以完美的解决这个问题了.

结语

当然这仅仅是一种解决的方案, 还有很多中解决方案使用队列的方式等, 希望这篇文章能帮到你.

猜你喜欢

转载自juejin.im/post/7031936738230534181