#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 二次封装的更多相关文章

  1. iOS项目相关@AFN&SDWeb的二次封装

    一,AFNetworking跟SDWebImge是功能强大且常用的第三方,然而在实际应用中需要封装用来复用今天就跟大家分享一下AFN&SDWeb的二次封装 1. HttpClient.h及.m ...

  2. iOS菜鸟之AFN的二次封装

    我用一个单例类将一些常用的网络请求进行了二次封装,主要包括post请求 get请求  图片文件上传下载  视频的断点续传等功能. 首先大家先去github上下载AFN,将文件夹内的AFNetworki ...

  3. Swift -- 对AFN框架的封装

    Swift -- 对AFN框架的封装 一.封装AFN的目的 简单的说: 解耦 日常工作中,我们一般都不会去直接使用AFNetWorking来直接发送网络请求,因为耦合性太强,假设有多个控制器都使用AF ...

  4. 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传)

    前言 首先声明一下,我这个是对WebUploader开源上传控件的二次封装,底层还是WebUploader实现的,只是为了更简洁的使用他而已. 下面先介绍一下WebUploader 简介: WebUp ...

  5. Quick Cocos (2.2.5plus)CoinFlip解析(MenuScene display AdBar二次封装)

    转载自:http://cn.cocos2d-x.org/tutorial/show?id=1621 从Samples中找到CoinFlip文件夹,复制其中的 res 和 script 文件夹覆盖新建工 ...

  6. 对jquery的ajax进行二次封装以及ajax缓存代理组件:AjaxCache

    虽然jquery的较新的api已经很好用了, 但是在实际工作还是有做二次封装的必要,好处有:1,二次封装后的API更加简洁,更符合个人的使用习惯:2,可以对ajax操作做一些统一处理,比如追加随机数或 ...

  7. Android 应用程序集成Google 登录及二次封装

    谷歌登录API:  https://developers.google.com/identity/sign-in/android/ 1.注册并且登录google网站 https://accounts. ...

  8. Android 应用程序集成FaceBook 登录及二次封装

    1.首先在Facebook 开发者平台注册一个账号 https://developers.facebook.com/ 开发者后台  https://developers.facebook.com/ap ...

  9. 对jquery的ajax进行二次封装

    第一种方法: $(function(){ /** * ajax封装 * url 发送请求的地址 * data 发送到服务器的数据,数组存储,如:{"username": " ...

随机推荐

  1. JavaScript 声明全局变量和局部变量

    JS中声明全局变量主要分为显式声明或者隐式声明下面分别介绍. 声明方式一: 使用var(关键字)+变量名(标识符)的方式在function外部声明,即为全局变量,否则在function声明的是局部变量 ...

  2. C#方法过滤器

    方法过滤器 使用Emit和注解属性Attribute实现 使用方式 1. 自定义方法过滤器 可分别定义方法执行前过滤器, 方法执行结束过滤器, 方法异常过滤器 执行前过滤器继承 ExecutingFi ...

  3. 安装win10 和win中的一些杂项问题

    reg中的 policies是政策/策略, 主要是指 控制面板中的一些控制项目, 其中 explorer是 控制面板的 显示项目... DWORD值是一个32位(4个字节:即双字)长度的数值, 是数字 ...

  4. P3181 [HAOI2016]找相同字符

    思路 广义SAM 把两个字符串建成广义SAM,然后统计两个SAM中相同节点的endpos大小乘积即可 记得开long long 代码 #include <cstdio> #include ...

  5. 【C#数据结构系列】图

    一:图 图状结构简称图,是另一种非线性结构,它比树形结构更复杂.树形结构中的结点是一对多的关系,结点间具有明显的层次和分支关系.每一层的结点可以和下一层的多个结点相关,但只能和上一层的一个结点相关.而 ...

  6. vi删除当前行的字符

    x 删除当前光标下的字符dw 删除光标之后的单词剩余部分.d$ 删除光标之后的该行剩余部分.dd 删除当前行

  7. 【Mac】【环境变量】

    Mac配置环境变量的地方  1./etc/profile   (建议不修改这个文件 )  全局(公有)配置,不管是哪个用户,登录时都会读取该文件.    2./etc/bashrc    (一般在这个 ...

  8. ubuntu中可以ping通IP地址但是ping不通域名的问题(www.baidu.com)

    治标不治本的办法:每次开机后执行sudo /etc/init.d/resolvconf restart就可以ping通. 治本方法见原博:https://blog.csdn.net/WFping518 ...

  9. 【快捷键】IntelliJ IDEA For Mac 常用快捷键

    一.符号对应关系 ⌃ control ⌥ option ⌘ command ⇧ shift 二.常用快捷键 1.control+shift+J 两行整理成一行 2.command+shift+F12 ...

  10. CodeForces - 363D --二分和贪心

    题目:CodeForces - 363D 题意:给定n个学生,其中每个学生都有各自的私己钱,并且自己的私己钱只能用在自己买自行车,不能给别人. 给定m个自行车,每个自行车都有一个价格. 给定公有财产a ...