#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. win7下Oracle库impdp导入dmp

    第一步:创建备份文件存储目录 create or replace directory back_file as 'D:\app\yangxf\back_or_memery_file'; create ...

  2. 基于token的身份验证JWT

    传统身份验证的方法 HTTP 是一种没有状态的协议,也就是它并不知道是谁是访问应用.这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证一下 ...

  3. IDEA的校园邮箱激活方式

    链接: https://blog.csdn.net/m0_37286282/article/details/78279060

  4. $O(n+log(mod))$求乘法逆元的方法

    题目 LOJ #152. 乘法逆元 2 题解 一个奇技淫巧qwq.可以离线求乘法逆元,效率\(O(n+log(mod))\). 考虑处理出\(s_n\)表示\(\prod_{i=1}^na_i\).以 ...

  5. [从零开始搭网站八]CentOS使用yum安装Redis的方法

    1.由于centOS官方yum源里面没有Redis,这里我们需要安装一个第三方的yum源,这里用了fedora的epel仓库 yum install epel-release 安装过程中会有让你确认的 ...

  6. vue的技巧代码

    转载:https://segmentfault.com/a/1190000014085613 第一招:化繁为简的Watchers 场景还原: created(){ this.fetchPostList ...

  7. JS中如何判断对象是对象还是数组

    JS中如何判断对象是对象还是数组 一.总结 一句话总结:typeof Array.isArray === "function",Array.isArray(value)和Objec ...

  8. [JavaScript] 设置函数同名变量为false会导致函数无法执行

    var findEmail=false; function findEmail(){ alert("findEmail");} 这样函数不会运行. 为了保证函数可以运行,修改为: ...

  9. web前端常见面试题汇总

    一.理论知识 1.1.讲讲输入完网址按下回车,到看到网页这个过程中发生了什么 a. 域名解析 b. 发起TCP的3次握手 c. 建立TCP连接后发起http请求 d. 服务器端响应http请求,浏览器 ...

  10. grpc(三)之grpc客户端使用连接池

    本文使用commons-pool2来实现连接池应用 1.定义一个产生连接池的工厂,需要继承BasePooledObjectFactory,其用处是生产和销毁连接池中保存的对象.根据需求,现在池子里保存 ...