#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. svg(二)---半瓶子晃荡

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. minicom 安装 查看串口

    因为现在电脑基本不配备串行接口,所以,usb转串口成为硬件调试时的必然选择.目前知道的,PL2303的驱动是有的,在dev下的名称是ttyUSB0 默认情况下ubuntu已经安装了USB转串口驱动(p ...

  3. Linux下修改用户的UID、GID

    01.用户的UID和GID不能被占用 [root@26 ~]# id mvpuid=503(mvp) gid=503(mvp) groups=503(mvp) ###假定我需要设置mvp的uid/gi ...

  4. TeXstudio+TexLive交叉引用

    LaTeX 交叉引用系统简介 https://www.cnblogs.com/wenbosheng/p/9537774.html 一般来说需要两次运行排版命令才能生成引用编号.背后的原理是这样的,第一 ...

  5. C++类的大小计算

    转自http://www.tuicool.com/articles/uiUJry 一个空的class在内存中多少字节?如果加入一个成员函数后是多大?这个成员函数存储在内存中什么部分? 一个Class对 ...

  6. 【转】 RGB各种格式

      转自:https://blog.csdn.net/LG1259156776/article/details/52006457?locationNum=10&fps=1 RGB组合格式 名字 ...

  7. guxh的python笔记四:迭代

    1,可迭代对象iterable,迭代器iterator,生成器generator 可迭代对象iterable: 实现__iter__方法的类.__iter__方法返回iterator或者generat ...

  8. Luffy之课程详情页

    Luffy之课程详情页 提前写好课程详情的template,并放入到Vue中 注册路由 import CourseDetail from "../components/CourseDetai ...

  9. Yet Another Maxflow Problem CodeForces - 903G (最小割,线段树)

    大意: 两个n元素集合$A$, $B$, $A_i$与$A_{i+1}$连一条有向边, $B_i$与$B_{i+1}$连一条有向边, 给定$m$条从$A_i$连向$B_j$的有向边, 每次询问修改$A ...

  10. 『TensorFlow』从磁盘读取数据

    十图详解TensorFlow数据读取机制 一.输入流水线读取数据流程 1). 创建文件名列表 相关函数:tf.train.match_filenames_once 2). 创建文件名队列 相关函数:t ...