AFN 二次封装
#import "YQDataManager.h"
#import <YYModel/YYModel.h>
#pragma mark - 数据model基类
@implementation YQListBaseModel
+ (NSDictionary *)modelCustomPropertyMapper
{
return @{};
}
@end
@implementation YQDataBaseModel
+ (NSDictionary *)modelCustomPropertyMapper
{
return @{};
}
@end
@implementation YQBaseModel
+ (NSDictionary *)modelCustomPropertyMapper
{
return @{};
}
@end
#pragma mark - 网络请求基类
///请求类型类型
typedef NS_ENUM(NSUInteger, YQNetWorkType) {
YQNetWorkTypeGet,//get请求
YQNetWorkTypeHttpPost,//入参Http格式Post请求
YQNetWorkTypeJsonPost,//入参json格式Post请求
};
/**
* 请求重试计数器
*/
@interface RetryCounter : NSObject
//重试次数,默认30次
@property (nonatomic, assign) NSInteger retryCount;
//已重试的次数
@property (nonatomic, assign) NSInteger retryTime;
//重试时间间隔,默认100毫秒
@property (nonatomic, assign) NSTimeInterval retryInterval;
//计算器id
@property (nonatomic, assign) NSInteger counterId;
- (instancetype)initWithHash:(NSUInteger)hash;
- (BOOL)canRetry;
@end
@implementation RetryCounter
- (instancetype)initWithHash:(NSUInteger)hash
{
self = [super init];
//set default value
self.retryCount = 1;
self.retryInterval = 0.1;
self.counterId = hash;
return self;
}
/**
* 是否可以重试,如果是,则返回true,并且重试次数自增1.
*
* @return 是否可以重试
*/
- (BOOL)canRetry {
BOOL result = (_retryTime < _retryCount);
if (result) {
_retryTime++;
}
return result;
}
@end
@interface YQDataManager ()
@property (nonnull, nonatomic, strong) NSMutableArray *retryCounterList;
@end
@implementation YQDataManager
/**
* 创建单例
*
* @return return value description
*/
+ (YQDataManager *)manager {
static YQDataManager *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.timeoutIntervalForRequest = 8.0;
configuration.timeoutIntervalForResource = 8.0;
/* 创建网络请求对象 */
sharedManager = [[YQDataManager alloc] initWithBaseURL:[NSURL URLWithString:BaseUrl] sessionConfiguration:configuration];
/* 设置请求和接收的数据编码格式 */
sharedManager.responseSerializer = [AFJSONResponseSerializer serializer]; // 设置接收数据为 JSON 数据
sharedManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
sharedManager.securityPolicy.allowInvalidCertificates = YES;
// 修改 解析数据格式 能够接受的内容类型 - 官方推荐的做法,民间做法:直接修改 AFN 的源代码
sharedManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json",@"text/javascript", @"text/html",nil];
sharedManager.retryCounterList = [NSMutableArray array];
});
return sharedManager;
}
#pragma mark - helper
- (RetryCounter*)retryCounterForHash:(NSUInteger)hash
{
RetryCounter *target = nil;
for (RetryCounter *counter in _retryCounterList) {
if (counter.counterId == hash) {
target = counter;
break;
}
}
return target;
}
- (RetryCounter*)insertCounterWithHash:(NSUInteger)hash
{
RetryCounter *counter = [[RetryCounter alloc] initWithHash:hash];
[[YQDataManager manager].retryCounterList addObject:counter];
return counter;
}
- (void)removeCounterForHash:(NSUInteger)hash
{
RetryCounter *counter = [self retryCounterForHash:hash];
if (counter != nil) {
[_retryCounterList removeObject:counter];
}
}
#pragma mark - http process
/**
* 重试的方法
*/
+ (void)networkMananger:(YQDataManager *)manager
method:(YQNetWorkType)httpMethod
retryWithUrl:(NSString*)url
params:(NSDictionary*)param
success:(void(^)(id responseData))successBlock
failure:(void(^)(NSError *error))failureBlock {
RetryCounter *currentCounter = [[YQDataManager manager] retryCounterForHash:param.hash];
if (currentCounter == nil) {
//add to retry counter list
currentCounter = [[YQDataManager manager] insertCounterWithHash:param.hash];
}
BOOL retryFlag = [currentCounter canRetry];
//wait for 10ms
NSDate *endDate = [NSDate dateWithTimeIntervalSinceNow:currentCounter.retryInterval];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate];
if (httpMethod == YQNetWorkTypeGet) {
[manager GET:url parameters:param progress:nil success:^(NSURLSessionDataTask *task, id responseData) {
successBlock(responseData);
//remove counter
[[YQDataManager manager] removeCounterForHash:param.hash];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
if (retryFlag) {
//retry
[YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:param success:successBlock failure:failureBlock];
} else {
failureBlock(error);
//remove counter
[[YQDataManager manager] removeCounterForHash:param.hash];
}
}];
}else if (httpMethod == YQNetWorkTypeJsonPost){
manager.requestSerializer = [AFJSONRequestSerializer serializer]; // 设置请求数据为 JSON 数据
[manager POST:url parameters:param progress:nil success:^(NSURLSessionDataTask *task, id responseData) {
successBlock(responseData);
//remove counter
[[YQDataManager manager] removeCounterForHash:param.hash];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
if (retryFlag) {
//retry
[YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:param success:successBlock failure:failureBlock];
} else {
failureBlock(error);
//remove counter
[[YQDataManager manager] removeCounterForHash:param.hash];
}
}];
}else{
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
[manager POST:url parameters:param progress:nil success:^(NSURLSessionDataTask *task, id responseData) {
successBlock(responseData);
//remove counter
[[YQDataManager manager] removeCounterForHash:param.hash];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
if (retryFlag) {
//retry
[YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:param success:successBlock failure:failureBlock];
} else {
failureBlock(error);
//remove counter
[[YQDataManager manager] removeCounterForHash:param.hash];
}
}];
}
}
/**
* 网络请求的底层方法
*/
+ (void)networkProcessWithUrl:(NSString *)url
params:(NSDictionary *)aParams
method:(YQNetWorkType )httpMethod
modelClass:(Class)modelClass
responseBlock:(YQNetworkResult)respBlock
{
YQDataManager *manager = [YQDataManager manager];
NSString *fullPath = [NSString stringWithFormat:@"%@%@",manager.baseURL,url];
if (aParams) {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:aParams options:0 error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"url : %@, param ==== %@", fullPath, jsonString);
}else{
NSLog(@"url : %@, param ==== %@", fullPath, aParams);
}
if (httpMethod == YQNetWorkTypeGet) {
if ([UserManager isLogin]) {
UserInfo *info= [UserManager getUserObject];
NSDictionary *headerFieldValueDictionary = @{@"token":info.token, @"usercode":info.userCode};
if (headerFieldValueDictionary != nil) {
for (NSString *httpHeaderField in headerFieldValueDictionary.allKeys) {
NSString *value = headerFieldValueDictionary[httpHeaderField];
[manager.requestSerializer setValue:value forHTTPHeaderField:httpHeaderField];
}
}
}
[manager GET:fullPath parameters:aParams progress:nil success:^(NSURLSessionDataTask *task, id responseData) {
[YQDataManager successProcessWithModelClass:modelClass result:responseData block:respBlock];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:aParams success:^(id respData) {
[YQDataManager successProcessWithModelClass:modelClass result:respData block:respBlock];
} failure:^(NSError *error) {
[YQDataManager failureProcess:error block:respBlock];
}];
}];
} else if (httpMethod == YQNetWorkTypeJsonPost) {
if ([UserManager isLogin]) {
UserInfo *info= [UserManager getUserObject];
NSDictionary *headerFieldValueDictionary = @{@"token":info.token, @"userMobile":info.userMobile};
if (headerFieldValueDictionary != nil) {
for (NSString *httpHeaderField in headerFieldValueDictionary.allKeys) {
NSString *value = headerFieldValueDictionary[httpHeaderField];
[manager.requestSerializer setValue:value forHTTPHeaderField:httpHeaderField];
}
}
}
manager.requestSerializer = [AFJSONRequestSerializer serializer]; // 设置请求数据为 JSON 数据
[manager POST:fullPath parameters:aParams progress:nil success:^(NSURLSessionDataTask *task, id responseData) {
[YQDataManager successProcessWithModelClass:modelClass result:responseData block:respBlock];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:aParams success:^(id respData) {
[YQDataManager successProcessWithModelClass:modelClass result:respData block:respBlock];
} failure:^(NSError *error) {
[YQDataManager failureProcess:error block:respBlock];
}];
}];
}else{
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
[manager POST:fullPath parameters:aParams progress:nil success:^(NSURLSessionDataTask *task, id responseData) {
[YQDataManager successProcessWithModelClass:modelClass result:responseData block:respBlock];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:aParams success:^(id respData) {
[YQDataManager successProcessWithModelClass:modelClass result:respData block:respBlock];
} failure:^(NSError *error) {
[YQDataManager failureProcess:error block:respBlock];
}];
}];
}
}
/**
* 接口请求成功返回
*/
+ (void)successProcessWithModelClass:(Class)modelClass
result:(id)responseData
block:(YQNetworkResult)block
{
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseData options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"====%@",jsonStr);
if (!block) {
return;
}
//model
if (modelClass == nil) {
if (block) {
block(YES, nil, responseData);
}
} else {
YQBaseModel *item = [YQBaseModel yy_modelWithJSON:responseData];
if ([item.status isEqualToString:@"SUCCESS"]) {//返回成功状态
if ([item.data isKindOfClass:[NSDictionary class]]) {
id model = [modelClass yy_modelWithJSON:item.data];
if (block) {
block(YES, item, model);
}
}else{
if (item.data) {
NSDictionary *josnDic = @{@"data":item.data };
id model = [modelClass yy_modelWithJSON:josnDic];
if (block) {
block(YES, item, model);
}
}else{
if (block) {
block(YES, item, nil);
}
}
}
}else{//返回失败状态
if (block) {
NSError *error = [YQDataManager errorWithDescription:item.message cede:item.code];
block(NO, item, error);
}
}
}
}
/**
* 接口请求失败无返回
*/
+ (void)failureProcess:(NSError *)error block:(YQNetworkResult)block
{
NSLog(@"error: %@,userInfo = %@",error, [error userInfo]);
if (block) {
block(NO, nil, error);
}
}
/**
* get方式请求调用方法
*/
+ (void)getDataWithUrl:(NSString *)url
Params:(NSDictionary *)params
modelClass:(Class)modelClass
responseBlock:(YQNetworkResult)respBlock
{
[YQDataManager networkProcessWithUrl:url params:params method:YQNetWorkTypeGet modelClass:modelClass responseBlock:respBlock];
}
/**
* post 请求调用方式 入参Json请求数据
*/
+ (void)postDataJsonRequestWithUrl:(NSString *)url
Params:(NSDictionary *)params
modelClass:(Class)modelClass
responseBlock:(YQNetworkResult)respBlock
{
[YQDataManager networkProcessWithUrl:url params:params method:YQNetWorkTypeJsonPost modelClass:modelClass responseBlock:respBlock];
}
/**
* post 请求调用方法 入参Http请求数据
*/
+ (void)postDataHttpRequestWithUrl:(NSString *)url
Params:(NSDictionary *)params
modelClass:(Class)modelClass
responseBlock:(YQNetworkResult)respBlock
{
[YQDataManager networkProcessWithUrl:url params:params method:YQNetWorkTypeHttpPost modelClass:modelClass responseBlock:respBlock];
}
#pragma mark - Utils
/**
* 请求成功返回失败状态时创建错误返回
*/
+ (NSError*)errorWithDescription:(NSString *)errorMsg cede:(NSInteger)code
{
NSString *msg = errorMsg;
if (msg == nil) {
msg = @"未知错误";
code = 22222;
}
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: msg};
NSError *error = [NSError errorWithDomain:@"dongze" code:code userInfo:userInfo];
return error;
}
@end
AFN 二次封装的更多相关文章
- iOS项目相关@AFN&SDWeb的二次封装
一,AFNetworking跟SDWebImge是功能强大且常用的第三方,然而在实际应用中需要封装用来复用今天就跟大家分享一下AFN&SDWeb的二次封装 1. HttpClient.h及.m ...
- iOS菜鸟之AFN的二次封装
我用一个单例类将一些常用的网络请求进行了二次封装,主要包括post请求 get请求 图片文件上传下载 视频的断点续传等功能. 首先大家先去github上下载AFN,将文件夹内的AFNetworki ...
- Swift -- 对AFN框架的封装
Swift -- 对AFN框架的封装 一.封装AFN的目的 简单的说: 解耦 日常工作中,我们一般都不会去直接使用AFNetWorking来直接发送网络请求,因为耦合性太强,假设有多个控制器都使用AF ...
- 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传)
前言 首先声明一下,我这个是对WebUploader开源上传控件的二次封装,底层还是WebUploader实现的,只是为了更简洁的使用他而已. 下面先介绍一下WebUploader 简介: WebUp ...
- Quick Cocos (2.2.5plus)CoinFlip解析(MenuScene display AdBar二次封装)
转载自:http://cn.cocos2d-x.org/tutorial/show?id=1621 从Samples中找到CoinFlip文件夹,复制其中的 res 和 script 文件夹覆盖新建工 ...
- 对jquery的ajax进行二次封装以及ajax缓存代理组件:AjaxCache
虽然jquery的较新的api已经很好用了, 但是在实际工作还是有做二次封装的必要,好处有:1,二次封装后的API更加简洁,更符合个人的使用习惯:2,可以对ajax操作做一些统一处理,比如追加随机数或 ...
- Android 应用程序集成Google 登录及二次封装
谷歌登录API: https://developers.google.com/identity/sign-in/android/ 1.注册并且登录google网站 https://accounts. ...
- Android 应用程序集成FaceBook 登录及二次封装
1.首先在Facebook 开发者平台注册一个账号 https://developers.facebook.com/ 开发者后台 https://developers.facebook.com/ap ...
- 对jquery的ajax进行二次封装
第一种方法: $(function(){ /** * ajax封装 * url 发送请求的地址 * data 发送到服务器的数据,数组存储,如:{"username": " ...
随机推荐
- JavaScript 声明全局变量和局部变量
JS中声明全局变量主要分为显式声明或者隐式声明下面分别介绍. 声明方式一: 使用var(关键字)+变量名(标识符)的方式在function外部声明,即为全局变量,否则在function声明的是局部变量 ...
- C#方法过滤器
方法过滤器 使用Emit和注解属性Attribute实现 使用方式 1. 自定义方法过滤器 可分别定义方法执行前过滤器, 方法执行结束过滤器, 方法异常过滤器 执行前过滤器继承 ExecutingFi ...
- 安装win10 和win中的一些杂项问题
reg中的 policies是政策/策略, 主要是指 控制面板中的一些控制项目, 其中 explorer是 控制面板的 显示项目... DWORD值是一个32位(4个字节:即双字)长度的数值, 是数字 ...
- P3181 [HAOI2016]找相同字符
思路 广义SAM 把两个字符串建成广义SAM,然后统计两个SAM中相同节点的endpos大小乘积即可 记得开long long 代码 #include <cstdio> #include ...
- 【C#数据结构系列】图
一:图 图状结构简称图,是另一种非线性结构,它比树形结构更复杂.树形结构中的结点是一对多的关系,结点间具有明显的层次和分支关系.每一层的结点可以和下一层的多个结点相关,但只能和上一层的一个结点相关.而 ...
- vi删除当前行的字符
x 删除当前光标下的字符dw 删除光标之后的单词剩余部分.d$ 删除光标之后的该行剩余部分.dd 删除当前行
- 【Mac】【环境变量】
Mac配置环境变量的地方 1./etc/profile (建议不修改这个文件 ) 全局(公有)配置,不管是哪个用户,登录时都会读取该文件. 2./etc/bashrc (一般在这个 ...
- ubuntu中可以ping通IP地址但是ping不通域名的问题(www.baidu.com)
治标不治本的办法:每次开机后执行sudo /etc/init.d/resolvconf restart就可以ping通. 治本方法见原博:https://blog.csdn.net/WFping518 ...
- 【快捷键】IntelliJ IDEA For Mac 常用快捷键
一.符号对应关系 ⌃ control ⌥ option ⌘ command ⇧ shift 二.常用快捷键 1.control+shift+J 两行整理成一行 2.command+shift+F12 ...
- CodeForces - 363D --二分和贪心
题目:CodeForces - 363D 题意:给定n个学生,其中每个学生都有各自的私己钱,并且自己的私己钱只能用在自己买自行车,不能给别人. 给定m个自行车,每个自行车都有一个价格. 给定公有财产a ...