ios 请求失败封装_IOS网络请求的简单封装设计

做ios项目已经几年了,最初是借用别人的框架,然后再框架上去修改。后来自己项目开始自己学着去写框架结构,不管是用什么样的框架,里面网络层的设计都是比较固定的,所以针对网络层的部分,我单独把这个地方进行了重构,整理成了现在的模样。现在把我的思路整理一下,希望大家如果有什么好的意见或者建议,可以提出来。共同进步。

1、整体思路

整体的思路也是沿用MVC的结构。将两部分内容进行的独立的封装:第一个是网络数据请求,第二个是对网络请求的调用和响应处理部分。而其中的C层,也就是controller部分,只需要处理最后响应回来的数据,进行View的操作即可。

同时因为在项目中考虑到了现在3种数据类型,定义了XML、JSON和ProtocolBuffer。

思路图

上面的图比较简单,只是为了表达一个思路,以及过程。

2、网络请求:NetworkRequest

这部分用的实现是AFNetworking,定义了一个单例的client,封装了client对于网络请求的调用。

先定义一个配置文件NetworkConfig和一个数据封装类NetManager。

// NetworkConfig.h

typedef NS_ENUM(NSInteger, NetErrorCode) {

NetErrorCodeEncryption = 1,//加密错误

NetErrorCodeDecryption = 2,//解密错误

NetErrorCode404 = 404,

NetErrorCode500 = 500,

NetErrorCodeTimeOut = 3,

NetErrorCodeDictionaryModel = 4,//字典数据转换为model数据时错误

NetErrorCodeOther = 5

};

typedef NS_ENUM(NSInteger, NetType) {

XML = 0,

JSON = 1,

PROTOBUF = 2,

};

typedef void (^ReturnValueBlock) (id returnValue);

typedef void (^ErrorCodeBlock) (NetErrorCode errorCode);

NetworkConfig.h文件中,定义了网络异常的类型、网络请求协议的类型,以及网络请求中的block块。在网络请求部分,我是用了block来处理网络请求的响应和异常返回的。

//NetManager.h

@interface NetManager : NSObject

/**

* 原始数据

* json和xml的返回类型为NSDictionary

* protocolBuffer则是NSData类型

*/

@property (nonatomic,strong) id rawData;

@property (nonatomic,assign) NetType type;//返回的数据类型

@end

NetManager的.m文件没有做具体的实现。这个类只是封装了网络请求的响应数据以及数据类型。这里的数据都是原始数据,方便后面中间层对数据的解析处理。

准备工作已经做好了,那么下面就是创建具体的网络请求部分了。先是单例模式的请求client。

//NetHttpRequestClient.h

@interface NetHttpRequestClient : AFHTTPSessionManager

+ (instancetype)sharedClient;

@end

//NetHttpRequestClient.m

@implementation NetHttpRequestClient

+ (instancetype)sharedClient {

static NetHttpRequestClient *_sharedClient = nil;

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

_sharedClient = [NetHttpRequestClient manager];

AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];

[securityPolicy setValidatesDomainName:NO];

_sharedClient.securityPolicy = securityPolicy;

_sharedClient.responseSerializer = [AFHTTPResponseSerializer serializer];

_sharedClient.requestSerializer.timeoutInterval = 40.0f;

});

return _sharedClient;

}

@end

client创建好了,就是网络请求的实现部分了。

#define SERVER_TYPE_XML @"xml/"

#define SERVER_TYPE_JSON @"json/"

#define SERVER_TYPE_PROTOBUF @"protobuf/"

@interface NetRequestClass : NSObject

#pragma 监测网络的可链接性

+ (BOOL) netWorkReachabilityWithURLString:(NSString *) strUrl;

#pragma POST请求

/**

*requestURLString:请求地址,不是全地址,由security+类型+方法名组合而成

*parameter:参数,参数中需要包含方法名的参数

*/

+ (NSURLSessionDataTask *) NetRequestPOSTWithRequestMethod: (NSString *) methodName

WithParameter: (NSDictionary *) parameter

WithRequestType:(NetType)type

WithReturnValeuBlock: (ReturnValueBlock) block

WithErrorCodeBlock: (ErrorCodeBlock) errorBlock;

#pragma protocol_buffer 的请求

/**

* protocol_buffer 的请求

*

* @param methodName 方法名

* @param data protocol_buffer请求的requestData数据

*

*/

+ (NSURLSessionDataTask *) NetProtocolBufferRequestPOSTWithRequestMethod: (NSString *) methodName

WithData: (NSData *) data

WithReturnValeuBlock: (ReturnValueBlock) block

WithErrorCodeBlock: (ErrorCodeBlock) errorBlock;

+(NSMutableDictionary *)addBasicParamters:(NSDictionary *)paramters;

@end

.h文件中,定义了三种类型,同时,将xml/json和protocolBuffer的请求分离开,因为在里面具体的实现部分有一点细微区别,所以没有将三者和在一起处理,而是分离开,方便后期维护。

//NetRequestClass.m

@implementation NetRequestClass

#pragma 监测网络的可链接性

+ (BOOL) netWorkReachabilityWithURLString:(NSString *) strUrl{

__block BOOL netState = NO;

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

NSOperationQueue *operationQueue = manager.operationQueue;

[manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

switch (status) {

case AFNetworkReachabilityStatusReachableViaWWAN:

case AFNetworkReachabilityStatusReachableViaWiFi:

[operationQueue setSuspended:NO];

netState = YES;

break;

case AFNetworkReachabilityStatusNotReachable:

netState = NO;

default:

[operationQueue setSuspended:YES];

break;

}

}];

[manager.reachabilityManager startMonitoring];

return netState;

}

#pragma --mark POST请求方式

+(NSURLSessionDataTask *)NetRequestPOSTWithRequestMethod:(NSString *) methodName

WithParameter:(NSDictionary *) parameter

WithRequestType:(NetType)type

WithReturnValeuBlock:(ReturnValueBlock) block

WithErrorCodeBlock:(ErrorCodeBlock) errorBlock{

NetHttpRequestClient *client = [NetHttpRequestClient sharedClient];

client.requestSerializer = [AFHTTPRequestSerializer serializer];

NSError *theError = nil;

NSString *requestContent = nil;

NSDictionary *allParameters = [self addBasicParamters:parameter];

[allParameters setValue:methodName forKey:@"name"];

switch (type) {

case XML:{//将参数数据转换为xml字符串

NSDictionary *requestDic = [NSDictionary dictionaryWithObject:[self formateXMLParameters:allParameters] forKey:@"methodRequest"];

requestContent = [requestDic innerXML];

}

break;

case JSON:{//将参数数据转换为jsonData

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:allParameters options:NSJSONWritingPrettyPrinted error:&theError];

requestContent = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

}

break;

default:

break;

}

NSString *encryptXml = @"加密后的字符串";

NSString *serverIpUrl = @"服务器地址";

NSDictionary *encryDic = [[NSDictionary alloc]initWithObjects:@[[NSNull null]] forKeys:@[encryptXml]];

NSString *requestUrl = [NSString stringWithFormat:@"%@%@%@",serverIpUrl,type == JSON?SERVER_TYPE_JSON:SERVER_TYPE_XML,methodName];

//启动请求

NSURLSessionDataTask *dataTask = [client POST:requestUrl parameters:encryDic progress:nil success:^(NSURLSessionDataTask *dataTask, id responseObject) {

if(dataTask){

[dataTask cancel];

dataTask = nil;

}

//获取得到的数据

NSString *theResponse = [[NSString alloc] initWithBytes:[responseObject bytes] length:[responseObject length] encoding:NSUTF8StringEncoding];

NSString *decryptStr = nil;

if(theResponse){

decryptStr = @"解密响应数据";

}

NetManager *manager = [[NetManager alloc]init];

NSDictionary *dataDoc = nil;

if(type == XML){

dataDoc = [NSDictionary dictionaryWithXMLString:decryptStr];

manager.type = XML;

}else if(type == JSON){

dataDoc = [decryptStr objectFromJSONStringWithParseOptions:JKParseOptionLooseUnicode];

manager.type = JSON;

}

manager.rawData = dataDoc;

block(manager);

} failure:^(NSURLSessionDataTask *dataTask, NSError *error) {

if(dataTask){

[dataTask cancel];

dataTask = nil;

}

NSInteger code = error.code;

if(code == NSURLErrorCancelled){//取消

return;

}else if(code == NSURLErrorTimedOut){//超时

errorBlock(NetErrorCodeTimeOut);

return;

}

NSDictionary *userInfo = error.userInfo;//NSURLErrorCancelled

NSHTTPURLResponse *response = userInfo[AFNetworkingOperationFailingURLResponseErrorKey];

if(response.statusCode == 404){

errorBlock(NetErrorCode404);

}else if(response.statusCode > 500){

errorBlock(NetErrorCode500);

}else{

errorBlock(NetErrorCodeOther);

}

}];

return dataTask;

}

+(NSMutableDictionary *)formateXMLParameters:(NSDictionary *)paramters{

NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:paramters];

for(NSString *key in paramters.allKeys){

NSObject *value = paramters[key];

[params removeObjectForKey:key];

if([value isKindOfClass:[NSString class]]){

[params setObject:value forKey:[NSString stringWithFormat:@"_%@",key]];

}else if([value isKindOfClass:[NSDictionary class]]){

NSDictionary *cp = [self formateXMLParameters:(NSDictionary *)value];

[params setObject:cp forKey:[NSString stringWithFormat:@"%@",key]];

}else if([value isKindOfClass:[NSArray class]]){

NSMutableArray *array = [NSMutableArray new];

for(NSDictionary *dic in (NSArray *)value){

NSDictionary *cp = [self formateXMLParameters:dic];

[array addObject:cp];

}

[params setObject:array forKey:[NSString stringWithFormat:@"%@",key]];

}

}

return params;

}

+(NSMutableDictionary *)addBasicParamters:(NSDictionary *)paramters{

NSMutableDictionary *params = nil;

if(paramters){

params = [[NSMutableDictionary alloc] initWithDictionary:paramters];

}else{

params = [[NSMutableDictionary alloc] init];

}

/***

为请求添加一些默认的基本信息,比如版本号,用户id等等。

**/

return params;

}

+(NSURLSessionDataTask *)NetProtocolBufferRequestPOSTWithRequestMethod:(NSString *)methodName WithData:(NSData *)data WithReturnValeuBlock:(ReturnValueBlock)block WithErrorCodeBlock:(ErrorCodeBlock)errorBlock{

NetHttpRequestClient *client = [NetHttpRequestClient sharedClient];

client.requestSerializer = [AFProtoBufRequestSerializer serializer];

NSDictionary *encryDic = [[NSDictionary alloc]initWithObjects:@[[NSNull null]] forKeys:@[data]];

NSString *serverIpUrl = @"服务器地址";

NSString *requestUrl = [NSString stringWithFormat:@"%@%@%@",serverIpUrl,SERVER_TYPE_PROTOBUF,methodName];

//启动请求

NSURLSessionDataTask *dataTask = [client POST:requestUrl parameters:encryDic progress:nil success:^(NSURLSessionDataTask *dataTask, id responseObject) {

if(dataTask){

[dataTask cancel];

dataTask = nil;

}

//获取得到的数据

NetManager *manager = [[NetManager alloc]init];

manager.rawData = responseObject;

manager.type = PROTOBUF;

block(manager);

} failure:^(NSURLSessionDataTask *dataTask, NSError *error) {

if(dataTask){

[dataTask cancel];

dataTask = nil;

}

NSInteger code = error.code;

if(code == NSURLErrorCancelled){//取消

return;

}else if(code == NSURLErrorTimedOut){//超时

if(errorBlock){

errorBlock(NetErrorCodeTimeOut);

}

return;

}

NSDictionary *userInfo = error.userInfo;//NSURLErrorCancelled

NSHTTPURLResponse *response = userInfo[AFNetworkingOperationFailingURLResponseErrorKey];

if(errorBlock){

if(response.statusCode == 404){

errorBlock(NetErrorCode404);

}else if(response.statusCode > 500){

errorBlock(NetErrorCode500);

}else{

errorBlock(NetErrorCodeOther);

}

}

}];

return dataTask;

}

上面的代码已经很完整了,就不用过多的解释。这是大家能够看到NetManager的作用了,在block的传递中,用的NetManager数据。

3、中间层NetworkModel

这层的主要作用是衔接ViewController与NetworkRequest两层,减少两层的耦合,封装处理网络请求返回的数据。

我们先定义了一个基类和一个协议。基类的作用是让所有实现网络数据处理的类都继承予它,而协议是为了衔接ViewController和NetworkModel之间,为网络数据的传递。

@protocol NetworkModelDelegate ;

@interface NetworkModelClass : NSObject

@property(nonatomic, weak, nullable) id delegate;

@end

@protocol NetworkModelDelegate

@optional

//用于xml或者json数据返回

- (void)networkModelWithNetResponse:(NSDictionary * _Nullable)response withMethodName:(NSString *)methodName;

- (void)networkModelWithNetError:(NetErrorCode)errorCode withMethodName:(NSString *)methodName;

//用于Protobuffer数据

- (void)networkModelWithNetDataResponse:(NSData * _Nullable)response withMethodName:(NSString *)methodName;

@end

这个类很简单,不需要过多的解释。

4、例子

好了,接下来举一个简单的使用例子,就可以明白是怎么工作的了。

创建了一个TestNetworkModel,其继承了NetworkModelClass,在里面,我们创建了两个对外的方法,为了方便,特地提供了一个关于protocolbuffer的使用。

//TestNetworkModel.h

@interface TestNetworkModel : NetworkModelClass

-(void)queryDataWithXML:(NSString *)para;

-(void)queryDataWithProtocolBuffer:(NSString *)para;

@end

//TestNetworkModel.m

@implementation TestNetworkModel{

NSURLSessionDataTask *_task1;

NSURLSessionDataTask *_task2;

}

-(void)queryDataWithXML:(NSString *)para{

if(_task1 && (_task1.state == NSURLSessionTaskStateRunning || _task1.state == NSURLSessionTaskStateSuspended)){

[_task1 cancel];

_task1 = nil;

}

NSDictionary *parameter = nil;

if(para){

parameter = [NSDictionary dictionaryWithObjectsAndKeys:para,@"key_para",nil];

}

__block typeof(self) weakSelf = self;

_task1 = [NetRequestClass NetRequestPOSTWithRequestMethod:@"方法名" WithParameter:parameter WithRequestType:XML WithReturnValeuBlock:^(id netManger){

[weakSelf anlyzeDataWithXML:((NetManager *)netManger).rawData];

} WithErrorCodeBlock:^(NetErrorCode errorCode){

[weakSelf networkError:@"方法名" withErrorCode:errorCode];

}];

}

-(void)anlyzeDataWithXML:(NSDictionary *)data{

/**

此处省略数据解析过程

*/

NSMutableDictionary *dataDic = nil;

NSString *methodName = nil;

if(self.delegate){

[self.delegate networkModelWithNetResponse:dataDic withMethodName:methodName];

}

}

-(void)queryDataWithProtocolBuffer:(NSString *)para{

if(_task2 && (_task2.state == NSURLSessionTaskStateRunning || _task2.state == NSURLSessionTaskStateSuspended)){

[_task2 cancel];

_task2 = nil;

}

NSData *data = nil;//封装的protocolbuffer的请求数据

__block typeof(self) weakSelf = self;

_task2 = [NetRequestClass NetProtocolBufferRequestPOSTWithRequestMethod:@"方法名" WithData:data WithReturnValeuBlock:^(id resp){

if (resp && [resp isKindOfClass:[NetManager class]]) {

NetManager *respData = (NetManager *)resp;

if(weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(networkModelWithNetDataResponse:withMethodName:)]){

[weakSelf.delegate networkModelWithNetDataResponse:respData.rawData withMethodName:@"方法名"];

}

}

} WithErrorCodeBlock:^(NetErrorCode errorCode){

[weakSelf networkError:@"方法名" withErrorCode:errorCode];

}];

}

-(void)networkError:(NSString *)methodName withErrorCode:(NetErrorCode)errorCode{

if(self.delegate){

[self.delegate networkModelWithNetError:errorCode withMethodName:methodName];

}

}

@end

上面的.m文件已经很明白了,通过delegate将网络请求的数据传递出去,而不需要关心delegate的实现者是谁。同时,此类中,对于网络数据的处理和解析,可以独自完成,以实现最大程度的独立封装。

接下来就是如何在ViewController中使用了。

//ViewController.h

@interface ViewController : UIViewController{

TestNetworkModel *_networkModel;

}

@end

//ViewController.m

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

_networkModel = [[TestNetworkModel alloc]init];

_networkModel.delegate = self;

[_networkModel queryDataWithXML:@"方法名1"];

[_networkModel queryDataWithProtocolBuffer:@"方法名2"];

}

#pragma mark - 网络请求的返回s

- (void)networkModelWithNetDataResponse:(NSData *)response withMethodName:(NSString *)methodName{

}

- (void)networkModelWithNetResponse:(NSDictionary *)response withMethodName:(NSString *)methodName{

}

- (void)networkModelWithNetError:(NetErrorCode)errorCode withMethodName:(NSString *)methodName{

}

@end

上面已经很清楚了,ViewController通过对TestNetworkModel的实例来发起网络请求,网络请求的数据通过TestNetworkModel中的delegate,也就是ViewController来处理网路请求解析后的数据,以供View的处理和显示。

至此,整个流程已经完整了,写的比较简单,只为了告诉大家这个实现的过程而已。其实,如果不想数据这么直接暴露给ViewController,实际可以在ViewController和NetworkModel直接再创建一层对数据的加工和逻辑处理层,而只暴露给ViewController需要显示的东西。

其实用NetworkModel的思路,也是为了方便网络请求的重用,同一个请求可能再多个地方调用,这样只需要在不同的地方创建不同的NetworkModel实例就可以了,最大程度的减少耦合。

你可能感兴趣的:(ios,请求失败封装)