場景描述:我們同時(shí)發(fā)出了a、b琳水、c 3個(gè)網(wǎng)絡(luò)請求肆糕,我們希望在a、b在孝、c 3個(gè)網(wǎng)絡(luò)請求都結(jié)束的時(shí)候獲得一個(gè)通知诚啃。
常見解決方法:通過度娘目前找到兩種做法;1浑玛、通過添加標(biāo)識來判斷請求是否全部結(jié)束 2绍申、dispatch_group + 信號量
本篇文章demo
1、添加標(biāo)識的解決方法
在遇到這個(gè)問題時(shí)首先想到了猿題庫團(tuán)隊(duì)開源的網(wǎng)絡(luò)框架YTKNetwork顾彰,然后閱讀源碼發(fā)現(xiàn)YTKNetwork是通過添加標(biāo)識來實(shí)現(xiàn)網(wǎng)絡(luò)請求的批量請求處理极阅;
話不多說直接上代碼在YTKNetwork里負(fù)責(zé)進(jìn)行網(wǎng)絡(luò)批處理請求的是YTKBatchRequest類,下面看下它的使用示例:
- (void)sendBatchRequest {
GetImageApi *a = [[GetImageApi alloc] initWithImageId:@"1.jpg"];
GetImageApi *b = [[GetImageApi alloc] initWithImageId:@"2.jpg"];
GetImageApi *c = [[GetImageApi alloc] initWithImageId:@"3.jpg"];
GetUserInfoApi *d = [[GetUserInfoApi alloc] initWithUserId:@"123"];
YTKBatchRequest *batchRequest = [[YTKBatchRequest alloc] initWithRequestArray:@[a, b, c, d]];
[batchRequest startWithCompletionBlockWithSuccess:^(YTKBatchRequest *batchRequest) {
NSLog(@"succeed");
NSArray *requests = batchRequest.requestArray;
GetImageApi *a = (GetImageApi *)requests[0];
GetImageApi *b = (GetImageApi *)requests[1];
GetImageApi *c = (GetImageApi *)requests[2];
GetUserInfoApi *user = (GetUserInfoApi *)requests[3];
// deal with requests result ...
NSLog(@"%@, %@, %@, %@", a, b, c, user);
} failure:^(YTKBatchRequest *batchRequest) {
NSLog(@"failed");
}];
}
先調(diào)用初始化方法把4個(gè)網(wǎng)絡(luò)請求的實(shí)例塞進(jìn)去YTKBatchRequest *batchRequest = [[YTKBatchRequest alloc] initWithRequestArray:@[a, b, c, d]]
涨享,看下這個(gè)初始化方法
- (id)initWithRequestArray:(NSArray *)requestArray {
self = [super init];
if (self) {
_requestArray = [requestArray copy];
_finishedCount = 0;
for (YTKRequest * req in _requestArray) {
if (![req isKindOfClass:[YTKRequest class]]) {
YTKLog(@"Error, request item must be YTKRequest instance.");
return nil;
}
}
}
return self;
}
我們看到有一個(gè)_finishedCount的變量根據(jù)字面很好理解是用來記錄請求完成的個(gè)數(shù)筋搏,然后我們?nèi)炙严逻@個(gè)變量,發(fā)現(xiàn)只有在下面的這個(gè)方法中用到了這個(gè)變量
- (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];
}
}
上述方法是網(wǎng)絡(luò)請求結(jié)束的回調(diào)代理方法厕隧,完成后_finishedCount計(jì)數(shù)加1奔脐,然后和保存網(wǎng)絡(luò)請求實(shí)例的數(shù)組元素個(gè)數(shù)進(jìn)行比較如果相等說明所有的請求都已經(jīng)完成,調(diào)用回調(diào)的代理方法及block請求結(jié)束吁讨。
然后YTKNetwork對于批量網(wǎng)絡(luò)請求失敗的處理是髓迎,只要一個(gè)失敗就立即停止請求,調(diào)用失敗回調(diào):
- (void)requestFailed:(YTKRequest *)request {
[self toggleAccessoriesWillStopCallBack];
// Stop
for (YTKRequest *req in _requestArray) {//遍歷請求實(shí)例數(shù)組
[req stop];//停止請求
}
// Callback //回調(diào)
if ([_delegate respondsToSelector:@selector(batchRequestFailed:)]) {
[_delegate batchRequestFailed:self];
}
if (_failureCompletionBlock) {
_failureCompletionBlock(self);
}
// Clear
[self clearCompletionBlock];
[self toggleAccessoriesDidStopCallBack];
[[YTKBatchRequestAgent sharedInstance] removeBatchRequest:self];
}
總結(jié):YTKNetwork的做法大致就是用一個(gè)變量記錄完成請求的個(gè)數(shù)建丧,然后在單個(gè)網(wǎng)絡(luò)請求結(jié)束回調(diào)的時(shí)候判斷當(dāng)前完成的網(wǎng)絡(luò)請求個(gè)數(shù)是否和總的網(wǎng)絡(luò)請求個(gè)數(shù)相等排龄,如果相等則說明請求結(jié)束。
2翎朱、dispatch_group + 信號量
參考文章
參考文章采用的是group + 信號量橄维,下面示例采用dispatch_group_enter尺铣、dispatch_group_leave實(shí)現(xiàn)詳見 本篇文章demo。
- (void)loadRequest1
{
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_group_enter(dispatchGroup);
[MALAFNManger getDataWithUrl:Url1 parameters:nil finish:^(RequestResult *result) {</br>
NSLog(@"第一個(gè)請求完成");
dispatch_group_leave(dispatchGroup);
} des:@"第一個(gè)url"];
dispatch_group_enter(dispatchGroup);
[MALAFNManger getDataWithUrl:Url2 parameters:nil finish:^(RequestResult *result) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(10);//網(wǎng)絡(luò)請求結(jié)束后回調(diào)是在主線程如果sleep放在外面會(huì)阻塞主線程
NSLog(@"第二個(gè)請求完成");
dispatch_group_leave(dispatchGroup);
});
} des:@"第二個(gè)url"];
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
NSLog(@"請求完成");
});
}