您的位置:首页 > 理论基础 > 计算机网络

基于AFNetWorking搭建APP的网络请求框架[iOS]

2015-10-19 17:28 567 查看
自从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请求:

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表单请求:

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多参数请求:

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);
});
}

四:综述
设计一:
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);
}];
}

2:如果operation不需要单独处理,可以再创建一个类CQNetWork.h,集成自基类。这个类,就是外界请求,使用的类。一些网络相关的方法例如获取网络状态可以放到这里面完成。另外,最重要的是,我们可以在这个类里面,使用上面
CQHttpClient
的写出公共的方法,不需要外界关注operation的概念,直接完成一个请求

[/code]

- (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的概念的。将其抛给外界即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: