#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. 王之泰201771010131《面向对象程序设计(java)》第六周学习总结

    第一部分:理论知识学习部分 第五章 第五章学习内容主要分为七个模块,分别为: 1.类.超类和子类: a. 类继承的格式: class 新类名extends已有类名. b. 已有类称为:超类(super ...

  2. hduoj 1002 A + B Problem II

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1002 题目描述如下: A + B Problem II Time Limit: 2000/1000 M ...

  3. PotPlayer安装与配置

    目录 1.简介 2.安装 3.设置 基本选项设置: 播放选项设置: PotPlayer皮肤设置: 1.简介 PotPlayer一款小巧简单的视频播放软件,具有于强大的定制能力和个性化功能. 2.安装 ...

  4. 理解SSL、HTTPS原理中的对称加密与非对称加密

    1.对称性加密 双方使用的同一个密钥,既可以加密又可以解密,这种加密方法称为对称加密,也称为单密钥加密. 简单来说就是:加密与解密都是同一个秘钥.   优点:通常在消息发送方需要加密大量数据时使用,算 ...

  5. Hbasewindows系统下启动报错及解决办法

    今天在本地windows电脑上,装pinpoint时,需要先安装一个Hbase数据库,按照教程下载启动Hbase数据库时,却启动报错:java.io.IOException: Could not lo ...

  6. Django 编写模板并渲染的示例

    >>> from django.template import Template, Context >>> raw_template = ""& ...

  7. 通过RequestContextHolder直接获取HttpServletRequest对象

    问题 朋友遇到一个问题:他想在Service方法中使用HttpServletRequest的API,但是又不想把HttpServletRequest对象当作这个Service方法的参数传过来,原因是这 ...

  8. linux存储管理之逻辑卷

    LVM管理 ====================================================================================创建LVMVG扩展/ ...

  9. MVC实战之排球计分(六)—— 使用EF框架,创建Controller,生成数据库。

    在上篇博客我们写到,此软件的数据库连接我们使用的是EF框架,code first模式下, 通过模型类,在创建controller的时候直接生成数据库,完成数据库的连接,与操作. 在使用EF框架之前,我 ...

  10. Win10安装CAD2006

    以管理员身份运行 提示如下问题: 查看该隐藏文件如下: 开始以为是未安装MSI Runtime 3.0和.NET Framework Runtime 1.1的原因,下载并安装后还是提示如上问题. 仔细 ...