近两个月,因为团队后台的动荡,项目新版本的接口非常乱,出现一个tableView需要几个接口来获取数据源的情况。这就需要在几个接口并发请求完后一起回调处理。
因为项目中使用的是AFN的网络框架,所以,这个需求只能基于AFN去实现
一般,我们在使用AFN的网络请求时,是利用
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
+(void)testRequest1{
NSDictionary * params;
[[AFNAsynNetwork sharedClient] POST:URL1 parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
data1 = responseObject;
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
[[AFNAsynNetwork sharedClient] POST:URL2 parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
data2 = responseObject;
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
[[AFNAsynNetwork sharedClient] POST:URL3 parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
data3 = responseObject;
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
}
+(void)testResult1{
if (data1 && data2 && data3) {
//数据整合操作
}
}
由于是反面教材,所以这里写的比较粗暴,想要优雅点可以使用CGD或者NSOperation的并发。这样写的话,数据处理的操作都是在block回调主线后做的,有人会说,可以再让这些数据去子线做操作,当然,这些我也有考虑。总之,这样去实现,代码质量很差,而且对于大量接口和大量数据的处理的扩展性不高。于是,我只能另辟蹊径。
在AFN3.0中,网络请求已经都改成了NSURLSession。如果对NSURLSession有所了解的话,会知道NSURLSession的网络请求回调是在NSURLSessionDataDelegate中回调的
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data;
而且,不一定是一次返回所有数据,需要用
NSMutableData去多次接收。在AFN中,其实已经将这个代理方法封装成了block,而且这个方法中获取的数据是在子线程中的,可以将请求到的数据直接拿出来在子线程中做数据操作,只要完成数据操作,在最后回调给主线程即可。
- (void)setDataTaskDidReceiveDataBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block
+(void)getDataBlock:(block)block{
NSMutableArray * dataArray = [NSMutableArray array];
NSMutableArray * errors = [NSMutableArray array];
//两个不需要回调的网络请求
NSURLSessionDataTask * task1 = [AFNAsynPost asynPostProductWithBlock:nil];
NSURLSessionDataTask * task2 = [AFNAsynPost asynPostBanner];
NSArray * requestArr = @[task1,task2];
__block NSInteger requestCount = 0;
[self getSuccessAndFailure:^(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data, NSError *error) {
requestCount++;
if (data) {
id json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
if ([json[@"respCode"] isEqualToString:@"00"]) {
if (dataTask.taskIdentifier == task1.taskIdentifier) {
[dataArray addObject:json];
}else{
NSLog(@"%@", json);
[dataArray addObject:json];
}
}else{
[errors addObject:json];
}
if (requestCount == requestArr.count) {
block(dataArray, errors);
}
}
if (error) {
[errors addObject:error];
if (requestCount == requestArr.count) {
block(dataArray, errors);
}
}
}];
}
//中间变量,用于区分不同接口返回的数据
NSUInteger tempTaskIdentifier;
//用于拼接一个接口多次返回的数据
NSMutableData * tempData;
+(void)getSuccessAndFailure:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data,NSError *error))block{
AFNAsynNetwork * manager = [AFNAsynNetwork sharedClient];
[manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
if (tempTaskIdentifier != dataTask.taskIdentifier) {
tempTaskIdentifier = dataTask.taskIdentifier;
tempData = [NSMutableData data];
}
[tempData appendData:data];
NSLog(@"接收到服务器的数据(可能调用多次):%s\n%@\n%lf", __func__, data, (double)dataTask.countOfBytesExpectedToReceive);
NSLog(@"json解析:%@",data);
if (data) {
id json = [NSJSONSerialization JSONObjectWithData:tempData options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves error:nil];
NSLog(@"%@",json);
block(session, dataTask,data,nil);
}
}];
[manager setTaskDidCompleteBlock:^(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSError * _Nullable error) {
NSLog(@"error:%@",error.localizedDescription);
if (error) {
block(session,(NSURLSessionDataTask *)task,nil,error);
}
}];
}