现实开发中,经常会遇到这样的需求,一个页面需要批量发送几个网络请求,并且对这几个网络请求进行统一处理。这种情况直接用AFNetworking实现不了,需要对其进行进一步的封装。
实现思路:
- 把要批量发送的请求放入一个数组,遍历数组,依次发送请求,定义一个已完成的请求数量计数器,每个请求完成是对该计数器加一,然后判断计数器是否和请求数组的请求个数一致,如果一致则代表请求完成。
- 跟第一个方法相似,只是判断请求完成的方法不同,使用GCD的信号量dispatch_semaphore,配合dispatch_group来实现。
下面来具体的讲述以上两种方法:
1. 通过请求计数器来判断 :
猿题库开源的网络库框架YTKNetwork里面处理批量请求就是用这种方法,它有一个类YTKBatchReques,就是用来实现批量请求的,它实现了一个方法requestFinished,该方法对已完成的请求数量_finishedCount进行自增,然后判断其是否与请求数组_requestArray中的请求个数相等,若相等则执行一系列批量请求完成的操作。
- (void)requestFinished:(YTKRequest *)request {
_finishedCount++;
if (_finishedCount == _requestArray.count) {
[self toggleAccessoriesWillStopCallBack];
if ([_delegate respondsToSelector:@selector(batchRequestFinished:)]) {
[_delegate batchRequestFinished:self];
}
if (_successCompletionBlock) {
_successCompletionBlock(self);
}
[self clearCompletionBlock];
[self toggleAccessoriesDidStopCallBack];
[[YTKBatchRequestAgent sharedInstance] removeBatchRequest:self];
}
}
2. GCD信号量dispatch_semaphore:
首先了解下信号量的几个方法
1.dispatch_semaphore_create(long value);
创建信号量,传入的value值要大于等于0,返回一个信号量
2.dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
如果信号量的value值大于0,则会往下执行并将value的值减1,否则,阻碍当前线程并等待timeout后再往下执行。如果等待的期间desema的值被dispatch_semaphore_signal函数加1了,且该函数所处线程获得了信号量,那么就继续向下执行并将信号量减1。如果等待期间没有获取到信号量或者信号量的值一直为0,那么等到timeout时,其所处线程会自动往下执行。
3.dispatch_semaphore_signal(dispatch_semaphore_t dsema);
返回值为long类型,当返回值为0时表示当前并没有线程等待其处理的信号量,其处理的信号量的值加1即可。当返回值不为0时,表示其当前有(一个或多个)线程等待其处理的信号量,并且该函数唤醒了一个等待的线程(当线程有优先级时,唤醒优先级最高的线程;否则随机唤醒)。
实现过程:
- 创建一个任务组dispatch_group
dispatch_group_t group = dispatch_group_create();
- 将每个请求包装成一个任务异步提交到任务组里,每个任务在一开始创建一个信号量,value值为0,任务最后在网络请求完成前进行信号量的等待,如果网络请求完成,则调用 'dispatch_semaphore_signal(semaphore);'对信号值加1,则线程不再进行信号量的等待,继续往下执行。当所有请求都完成时,会在dispatch_group_notify里的回调进行相应的处理。
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
// 创建信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSURLSessionDataTask *task = [manager GET:service.url parameters:service.parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// 如果请求成功,增加信号量值
dispatch_semaphore_signal(semaphore);
// 成功回调 主线程执行
dispatch_async(dispatch_get_main_queue(), ^{
!service.requestComplete?:service.requestComplete(responseObject,nil);
});
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// 如果请求失败,增加信号量值
dispatch_semaphore_signal(semaphore);
}];
// 在网络请求任务成功之前,信号量等待中
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 所有请求完成时回调
});
参考链接
http://www.cnblogs.com/snailHL/p/3906112.html
https://github.com/yuantiku/YTKNetwork