关于AFNetworking请求封装的思考与实践
来源:互联网 发布:js onclick事件传参 编辑:程序博客网 时间:2024/06/06 07:52
使用AFNetworking
已经有将近三四年的时间,从最初的AFNetworking 2.x
到现在的AFNetworking 3.1.0
。AFNetworking
已经成为开发iOS项目的必备第三方库之一,不得不说它给开发者节省了大量的开发时间。网上有很多不同的关于AFNetworking
的封装代码,但是都存在这这样的或那样的问题,下面是我开发app时封装用法,有不同见解的欢迎在下方留言。
一个好的AFNetworking
网络请求框架应该具备的特征
1 良好的封装性,开发时方便快速接入2 接口变更时便于修改 3 适于多版本迭代开发4 出现问题时方便定位修改
下面是我封装的AFNetworking
网络请求引擎文件目录
扩展后的封装类是这样的,不同的版本的接口可以分成几个不同的文件
LSNetWorkManagerInterface.h 文件
主要存放app
所有接口的参数
主要内容如下,使用这种方案的好处在于使用Interface[kServletLogin]
取出接口的变动地址,且统一方便管理,后续版本升级时只需再声明一个个枚举和字符串数组就能轻松方便使用
#ifndef LSNetWorkManagerHeader_h#define LSNetWorkManagerHeader_h/** * 1.6版本接口,与后台版本号,teambition保持一致 */static NSString * const Interface[] = { @"", @"user/appLogin", // servlet用户登陆};/* HTTP接口对应的标识 */typedef NS_ENUM(NSUInteger, InterfaceAction) { kNull = 0, kServletLogin, //servlet用户登陆};#endif /* LSNetWorkManagerHeader_h */
LSBaseNetWorking.h
文件
主要包含了请求的服务器返回码kStatusCode
,数据字段kResData
,STATUS_CODE
请求返回的服务器与客户端约定的状态码,公开了两个方法分别对应GET
方法与POST
方法,其他的解释说明可以参看下面代码
#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>#import "LSConstants.h"#define kStatusCode @"status"#define kResData @"resData"#define LOAD_DATA_PAGESIZE 10typedef NS_ENUM(NSInteger, STATUS_CODE) { STATUS_CODE_CUSTOM_ERROR = - 10000, STATUS_CODE_FAILED = - 11001,//网络异常类型 STATUS_CODE_SUCCESS = 200,//接口调用成功 STATUS_CODE_NEED_CHARGE = 10088,//};//额外存储数据时使用typedef void(^RES_SUCC_OPERATION_BLOCK)(id data);/** * 封装二次请求到dataController时的处理 * * @param success 请求是否成功 * @param resultData 回调数据 */typedef void(^RES_SIM_CALLBACK)(BOOL success,id resultData);typedef void(^RES_SUCC_BLOCK)(id data);/** * 请求失败回调 * * @param resStatus 服务请请求返回状态码(主)、网络异常导致的失败也包括、不包括STATUS_CODE_SUCCESS * @param data 暂时为字符串类型,包括@“当前网络异常,请稍后重试!” */typedef void(^RES_FAIL_BLOCK)(NSInteger resStatus,id data);@interface LSBaseNetWorking : NSObject- (void)getHTTPRequestWithUrlString:(NSString *)urlStr parameters:(NSDictionary *)paraDic success:(RES_SUCC_BLOCK)succ failure:(RES_FAIL_BLOCK)fail;- (void)postHTTPRequestWithUrlString:(NSString *)urlStr parameters:(NSDictionary *)paraDic success:(RES_SUCC_BLOCK)succ failure:(RES_FAIL_BLOCK)fail;@end
LSBaseNetWorking.m
文件
printHTTPUrlWithUrl:parameters:
该方法主要是打印你的请求字符串用以方便在控制台查看,定位问题。 requestHTTPRequestWithReqType:UrlString:parameters:operation:success:failure:
方法里面封装的主要是AFNetworking的常用GET与POST方法,其中RES_SUCC_OPERATION_BLOCK
主要是数据持久化层需要使用到的,一般不常使用
#import "LSBaseNetWorking.h"#import "AFNetworking.h"#import "AFNetworkActivityIndicatorManager.h"typedef NS_ENUM(NSUInteger, HttpRequestType) { DoGet, DoPost,};@interface LSBaseNetWorking ()@property (nonatomic, strong) AFHTTPSessionManager* httpManager;@end@implementation LSBaseNetWorking- (instancetype)init{ self = [super init]; if (self) { // [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES]; _httpManager = [[AFHTTPSessionManager alloc]initWithBaseURL:[NSURL URLWithString:BASE_URL_STR]]; NSSet *set = [NSSet setWithObjects:@"text/html",@"text/plain",@"application/json", nil]; _httpManager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; _httpManager.responseSerializer.acceptableContentTypes = set; [_httpManager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { NSLog(@"Reachability = %ld",(long)status); switch (status) { case AFNetworkReachabilityStatusReachableViaWWAN: case AFNetworkReachabilityStatusReachableViaWiFi:// [operationQueue setSuspended:NO]; NSLog(@"network is now changed Reachable!!!"); break; case AFNetworkReachabilityStatusNotReachable:// [operationQueue setSuspended:YES]; NSLog(@"network is now changed NotReachable!!!"); break; default: break; } }]; [_httpManager.reachabilityManager startMonitoring]; } return self;}- (void)printHTTPUrlWithUrl:(NSString *)url parameters:(NSDictionary *)parameters{ NSString *httpUrl = @""; NSString *dicKey = nil; for (int i = 0; i < [[parameters allKeys] count]; i++) { httpUrl = i == 0 ? @"?" : [httpUrl stringByAppendingString:@"&"]; dicKey = [parameters allKeys][i]; httpUrl = [httpUrl stringByAppendingFormat:@"%@=%@", dicKey, parameters[dicKey]]; } //Warn httpUrl 非nil 否则追加会导致崩溃 httpUrl = [url stringByAppendingString:httpUrl]; NSLog(@"\n-----------------[HTTP Url]-----------------\n%@%@\ \n--------------------------------------------", BASE_URL_STR,httpUrl);}- (void)requestHTTPRequestWithReqType:(HttpRequestType)reqType UrlString:(NSString *)urlStr parameters:(NSDictionary *)paraDic operation:(RES_SUCC_OPERATION_BLOCK)operAction success:(RES_SUCC_BLOCK)succ failure:(RES_FAIL_BLOCK)fail{ void (^success)(NSURLSessionTask *operation, id responseObject) = ^(NSURLSessionTask *operation, id responseObject) { NSInteger statuscode = [responseObject[ kStatusCode ] integerValue]; id data = responseObject[kResData]; if (succ || fail) {//成功或失败有处理就进行打印 [self printHTTPUrlWithUrl:urlStr parameters:paraDic]; } if (statuscode == STATUS_CODE_SUCCESS) { if (operAction) { operAction(data); } if (succ) { NSLog(@"\nStatus:%li \n%@\n---------------------------------------", (long)statuscode, responseObject); succ(data); } }else { NSString *errorTipMsg = responseObject[kResData]; //调整输出模式,只有statuscode = 600提示且为字符串通通输出 if (statuscode == 600 && [errorTipMsg respondsToSelector:@selector(length)] && kStrProperty(errorTipMsg)) { }else if (statuscode == 601 && [errorTipMsg respondsToSelector:@selector(length)] && kStrProperty(errorTipMsg)) { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:errorTipMsg delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles: nil]; [alertView show]; } if (fail) { NSLog(@"responseObject error:%@", responseObject); fail([responseObject[kStatusCode] integerValue],data); } } }; void (^failure)(NSURLSessionTask *operation, NSError *error) = ^(NSURLSessionTask *operation, NSError *error) { if (succ && fail) {//成功失败都处理才进行打印 [self printHTTPUrlWithUrl:urlStr parameters:paraDic]; } NSLog(@"Error:%@", error); if (fail) { fail(STATUS_CODE_FAILED,@"当前网络异常,请稍后重试!"); } }; // 默认追加的参数 NSMutableDictionary *newParameters = [NSMutableDictionary dictionaryWithDictionary:paraDic]; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"参数值----%@\n", newParameters); }); if (reqType == DoGet) { [_httpManager GET:urlStr parameters:newParameters progress:nil success:success failure:failure]; } else if (reqType == DoPost){ [_httpManager POST:urlStr parameters:newParameters progress:nil success:success failure:failure]; }}- (void)postHTTPRequestWithUrlString:(NSString *)urlStr parameters:(NSDictionary *)paraDic success:(RES_SUCC_BLOCK)succ failure:(RES_FAIL_BLOCK)fail{ [self requestHTTPRequestWithReqType:DoPost UrlString:urlStr parameters:paraDic operation:nil success:succ failure:fail];}- (void)getHTTPRequestWithUrlString:(NSString *)urlStr parameters:(NSDictionary *)paraDic success:(RES_SUCC_BLOCK)succ failure:(RES_FAIL_BLOCK)fail{ [self requestHTTPRequestWithReqType:DoGet UrlString:urlStr parameters:paraDic operation:nil success:succ failure:fail];}@end
LSBaseNetWorking.h
文件
提供了一个单例方法,与一个登陆的事例,该类继承自LSBaseNetWorking
#import "LSBaseNetWorking.h"@interface LSNetWorkManager : LSBaseNetWorking+ (instancetype)shareInstance;//kServletLogin, //第三方用户登陆- (void)doReqLoginWithUserName:(NSString *)userName password:(NSString *)password success:(RES_SUCC_BLOCK)succ failure:(RES_FAIL_BLOCK)fail;@end
LSNetWorkManager.m
文件
介绍登陆接口的一种写法,可仿照此示例进行编写
#import "LSNetWorkManager.h"#import "MJExtension.h"#import "LSNetWorkManagerInterface.h"static LSNetWorkManager *networkManager = nil;@interface LSNetWorkManager ()@end@implementation LSNetWorkManager+ (instancetype)shareInstance{ @synchronized (self) { if (networkManager == nil) { networkManager = [[LSNetWorkManager alloc] init]; } } return networkManager;}+ (instancetype)allocWithZone:(NSZone *)zone{ @synchronized (self) { if (networkManager == nil) { networkManager = [super allocWithZone:zone]; } return networkManager; } return nil;}#pragma mark - HTTP request//kServletLogin, //用户登陆- (void)doReqLoginWithUserName:(NSString *)userName password:(NSString *)password success:(RES_SUCC_BLOCK)succ failure:(RES_FAIL_BLOCK)fail{ NSDictionary *params = @{@"userName" : userName, @"userPsw" : password, }; [self postHTTPRequestWithUrlString:Interface[kServletLogin] parameters:params success:succ failure:fail];}@end
下面是用法
-(IBAction)buttonClick :(UIButton *)butt{ NSString *userName = self.userNameTF.text; NSString *usePsw = self.userPswTF.text; [[LSNetWorkManager shareInstance] doReqLoginWithUserName:userName password:usePsw success:^(id data) { } failure:^(NSInteger resStatus, id data) { }];}
返回的数据时这样的
设计思想
每个方法都写一个接口看似是多了一些工作量,但是大部分内容都是复制粘贴的,然后修改一些接口和参数,方便后续重复调用。以前也使用过一段时间只封装一层提供两个接口(get+set)的方案,后续发现很多问题;
* 当接口多的时候,遇到问题进行调试,简直连断点都不知道往哪里打,返回错误的状态码也不知道是哪个接口返回的,所以个人不推荐使用那种只提供两个接口的方案。
* 然后就是接口的url地址随便乱写,想要修改接口不知道要找多少个类,还有很多接口重复写了多次。
* 参数乱写,很可能多写或者少写一个参数。
注意事项
1 _httpManager = [[AFHTTPSessionManager alloc]initWithBaseURL: [NSURL URLWithString:BASE_URL_STR]]; BASE_URL_STR不要忘记设置2 不同接口之间在数组中声明不要忘记写逗号,否则可能将他们拼装起来, 导致找到不到接口 404错误3 打印url接口不论是GET接口还是POST接口都是会打印成&链接的URL,请知悉。4 工程使用了cocoaspod,不了解的同鞋可上网搜索,网上很多教程
demo工程地址
- 关于AFNetworking请求封装的思考与实践
- AFNetworking 2.5.x 网络请求的封装
- 自己封装的afnetworking数据请求
- 二次封装AFNetworking的网络请求
- iOS AFNetworking封装的网络请求
- 关于封装的思考
- 封装网络请求(AFNetworking)
- AFNetWorking封装请求数据
- iOS开发:GET与POST接口网络请求以及对AFNetworking的二次封装
- AFNetworking数据请求(深度封装)
- 结合AFNetworking 和 MJExtension的二次网络请求的封装
- ASIFormDataRequest /AFNetworking GET/POST请求的简单封装(block)
- 基于AFNetworking封装的网络请求工具类
- 基于AFNetworking封装的网络请求工具类【转载】
- 一个完美封装AFNetworking的网络请求Demo
- iOS开发之网络请求(基于AFNetworking的再封装)
- iOS开发之网络请求(基于AFNetworking的再封装)
- 关于如何提高程序设计编码能力的思考与实践
- 工作学习笔记2017-04-19
- SharedPreferences封装
- Android源码解析之repo仓库
- shell编程 部分讲解
- 数据库事务相关知识总结
- 关于AFNetworking请求封装的思考与实践
- 安卓开源项目周报0419
- 简单实现的水波纹效果
- AbcABC
- s3c2440之uda1341声卡驱动以及madplay播放器移植
- poj 1157 LITTLE SHOP OF FLOWERS
- 二叉树根到叶路径
- 反射基础知识
- android退出整个程序的方法