自从AFNetWorking(下文简称AFN)更新2.0版本以后,AFN的许多的问题获得的有效的解决,写法也获得了完善。前期主流的第三方网络类库 ASI做者宣布再也不维护,国内大多数的主流APP都逐步接受并开始采用AFN。出于各自公司项目的不一样须要,你们都会在AFN的基础上加一层不尽相同的封 装。不少新APP在选择方式时也会很是纠结。如何封装才可让AFN更有效率更方便的应用于项目呢,对于这个问题,各人有各人的见解。基于作过以及读过的 几个项目,也来谈一下如何搭建一个APP的网络请求框架。因为本人水平有限,文章不免有不足之处,还请海涵并指正。
本文源地址:http://386502324.blog.163.com/blog/static/113469377201591211312665/
一:了解AFN的基本使用
经过AFN类库在Github的API文档,咱们能够大体知道AFN的基本用法。先看其API最基本的请求方式
Get请求:html
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; [manager GET:@"http://example.com/resources.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"JSON: %@", responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }];
POST表单请求:web
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; NSDictionary *parameters = @{@"foo": @"bar"}; NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"]; [manager POST:@"http://example.com/resources.json" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { [formData appendPartWithFileURL:filePath name:@"image" error:nil]; } success:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"Success: %@", responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }];
POST多参数请求:json
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; NSDictionary *parameters = @{@"foo": @"bar"}; NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"]; [manager POST:@"http://example.com/resources.json" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { [formData appendPartWithFileURL:filePath name:@"image" error:nil]; } success:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"Success: %@", responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }];
能够看到官方直接使用AFHTTPRequestOperationManager完成了请求的发起、完成等。AFHTTPRequestOperationManager这个类的做用,官方是这么说的:AFHTTPRequestOperationManager
encapsulates the common patterns of communicating with a web application over HTTP, including request creation, response serialization, network reachability monitoring, and security, as well as request operation management.AFHTTPRequestOperationManager封装了通用的模式去进行网络请求的建立、网络请求的响应、网络状态的监控、网络的安全设置、以及网络请求的管理。【笔者译】
二:项目中如何使用
AFHTTPRequestOperationManager的完全封装确实可以很是方便的完成一个网络请求。可是若是你想对于一个具体网络请求进行本身的特殊化定制,也就是对一个operation进行特殊处理。通常咱们会建立一个
继承自AFHTTPRequestOperation的子类好比命名为
CQHTTPRequestOperation。
在子类里,咱们能够给每个operation增长一个不一样标识。经过标识,咱们就能够从队列中拿到每个具体的网络请求,也就是某一个operation,对其进行你想要的处理。
固然,这个operation实际上仍是使用
数组AFHTTPRequestOperationManager进行建立、管理。下方的manager为其 实例。
operation= (CQNetWorkOperation *)[Manager GET:url parameters:parmar success:^(AFHTTPRequestOperation *operation, id responseObject) {
[weakSelf handleNewResponse:operation error:nil onCompletinBlock:completionBlock];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[weakSelf handleNewResponse:operation error:error onCompletinBlock:completionBlock];
}];
安全
网络
从第二部分的代码区能够看到,AFN以返回数据标识为结束。通常来讲,返回的都是data。可是咱们不想在每个网络请求中分别进行处理,有没有一种办法,统一处理返回的数据呢?固然能够的。在此推荐使用Mantle。三:数据处理
咱们能够新建一个类,专门用来处理数据的解析;例如,传入AFN请求后获得的data,而后统一处理。CQResponseResult为向外抛出的结果model。处理的第一步,校验一下data的可用性,根据返回的数据的类型,给model赋值成字典、数组字符串等。若是数据有问题,也能够给该model的相应属性赋值。固然最后不要忘掉的是,结果必定要放到主线程抛出。
+(void)parseOCResponseObject:(id)responseObject modelClass:(Class )modelClass error:(NSError *)error onCompletionBlock:(OCResponseResultBlock)completionBlock{
CQResponseResult *responseResult=[OCResponseResult responseResultWithOCResponseObject:responseObject error:error];
if (responseResult.responseData != nil && responseResult.responseData != [NSNull null]&&modelClass ){
if ([responseResult.responseData isKindOfClass:[NSDictionary class]]) {
NSError *aError;
MTLModel *dataModel=[MTLJSONAdapter modelOfClass:modelClass fromJSONDictionary:responseResult.responseData error:&aError];
if (dataModel&&nil==aError) {
responseResult.responseData=dataModel;
}
}else if ([responseResult.responseData isKindOfClass:[NSArray class]]){
responseResult.responseData = [MTLJSONAdapter modelsOfClass:modelClass fromJSONArray:responseResult.responseData error:nil];
}else if ([responseResult.responseData isKindOfClass:[NSString class]]){
//若是是字符串,暂时不作处理
}
}
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(responseResult);
});
}
app
四:综述
框架
设计一:
1:建立CQHttpClient类,继承自基类。用来处理manager和operation。
- (void )get:(NSString *)URLString parameters:(NSDictionary *)parameters
resultBack:(NetworkBackBlock)resultBack
{
NSMutableSet *contentTypes = [[NSMutableSet alloc] initWithSet:operationManager.responseSerializer.acceptableContentTypes];
if (contentTypes) {
[contentTypes addObject:@"text/html"];
[contentTypes addObject:@"application/json"];
}
operationManager.responseSerializer.acceptableContentTypes = contentTypes;
[operationManager GET:URLString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
CommonResult *result = [NWCommonResult resultWithData:MC_RESULT_CODE_SUCCESS resultDesc:nil];
DDLogInfo(@"operation::%@::::%@",parameters,operation.responseString);
resultBack(result, RESULT_OBJECT(operation));
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DDLogInfo(@"error::%@::::%@:::%@",parameters,operation.responseString,error);
CommonResult *result = [NWCommonResult resultWithData:MC_RESULT_CODE_FAILURE resultDesc:[error description]];
resultBack(result, nil);
}];
}async
2:若是operation不须要单独处理,能够再建立一个类CQNetWork.h,集成自基类。这个类,就是外界请求,使用的类。一些网络相关的方法例如获取网络状态能够放到这里面完成。另外,最重要的是,咱们能够在这个类里面,使用上面
postCQHttpClient
的写出公共的方法,不须要外界关注operation的概念,直接完成一个请求
- (void)post:(NSString *)urlString parameters:(NSMutableDictionary *)parameters isCache:(BOOL) isCache cacheTime:(NSTimeInterval)timeInterval resultBack:(NetworkBackBlock)resultBack
{
if (MC_NETWORK_STATUS_NONE == [self getNetworkStatus]) {
NWCommonResult *result = [NWCommonResult resultWithData:MC_RESULT_CODE_NETWORK_FAILURE resultDesc:nil];
resultBack(result, nil);
return;
}
CQHttpClient *httpClient = [self baseHttpRequest];
if (_config &&[_config respondsToSelector:@selector(getToken:)]) {
// [parameters setObject:[_config getToken:urlString] forKey:@"token"];
[httpClient addValue:[_config getToken:urlString] forHTTPHeaderField:@"Cookie"];
}
if (_config &&[_config respondsToSelector:@selector(getRequestUDID)]) {
httpClient.UDIDDate = [_config getRequestUDID];
NSLog(@"httpClient.UDIDDatehttpClient.UDIDDate:::%@",httpClient.UDIDDate);
}
/**
* 主要生成文件的名字
*/
_urlString = urlString;
_parameters = parameters;
_isCache = isCache;
_timeInteval = timeInterval;
if ([self compareSecondsLoadCache]) {
CommonResult *result = [NWCommonResult resultWithData:MC_RESULT_CODE_SUCCESS resultDesc:nil];
resultBack(result, [self cacheJson]);
return;
}
[httpClient post:urlString parameters:parameters resultBack:^(NWCommonResult *result, id responseObject) {
result.UDIDDate = httpClient.UDIDDate;
resultBack(result,responseObject);
}];
}
3:数据处理
+(CQResponseResult *)responseResultWithOCResponseObject:(id)responseObject error:(NSError *)aError{
CQResponseResult *responeResult=[[OCResponseResult alloc] init];
if (responseObject != nil && responseObject != [NSNull null]&&nil==aError ) {
if ([responseObject isKindOfClass:[NSDictionary class]]){
[CQResponseResult parseOCResponesDic:responseObject withResponseResut:&responeResult];
}else if([responseObject isKindOfClass:[NSData class]]){
NSError *jsonError;
NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableLeaves error:&jsonError];
if (dic&&nil==jsonError) {
[OCResponseResult parseOCResponesDic:dic withResponseResut:&responeResult];
}else{
responeResult.responseCode=OCCodeStateFailed;
responeResult.responseMessage=OCNetWorkErrorMessage;
}
}else if ([responseObject isKindOfClass:[NSString class]]){
NSData *aData=[responseObject dataUsingEncoding:4];
NSError *jsonError;
NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:aData options:NSJSONReadingMutableLeaves error:&jsonError];
if (dic&&nil==jsonError) { [OCResponseResult parseOCResponesDic:dic withResponseResut:&responeResult]; }else{ responeResult.responseCode=OCCodeStateFailed; responeResult.responseMessage=OCNetWorkErrorMessage; } }else{ responeResult.responseCode=OCCodeStateFailed; responeResult.responseMessage=OCNetWorkErrorMessage; } }else{ responeResult.responseCode=OCCodeStateFailed; responeResult.responseMessage=OCNetWorkErrorMessage; } return responeResult;}
设计二:
第二步中,外界仍是须要关注opreation的概念的。将其抛给外界便可。