代码地址: https://github.com/huangxiongbiao12/BGNetworking
1、封装AFNetworking基本请求方法
封装原因:当AFNetworking的api改变的时候只需要更改封装的方法,无需大面积改动代码(不封装直接用AFNetworking请求如果AFNetworking的api变化所有用的地方都需要变化)
代码依赖了MBProgressHUD,显示加载图
封装思路接口:
1、主要封装了Get Post请求带HUD和不带HUD的另外一个可以选择是否带HUD的接口
2、将上传图片的单独封装
3、封装了https加载证书验证的方法,只需要设置cer文件的路径名称,以及是否需要https验证
代码如下:
api
#import <Foundation/Foundation.h>
#import "NetStatusData.h"
@interface HttpRequstData : NSObject
+ (void)getUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
+(void)getNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
+(void)postUrl:(NSString*)url parameters:(NSDictionary*)parameters showHUD:(BOOL)show success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
+(void)postUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
+(void)postNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
+ (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
+ (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
@end
实现
#import "HttpRequstData.h"
/**
* 是否开启https SSL 验证
*
* @return YES为开启,NO为关闭
*/
#define openHttpsSSL YES
/**
* SSL 证书名称,仅支持cer格式。“app.bishe.com.cer”,则填“app.bishe.com”
*/
#define certificate @"public"
typedef NS_ENUM(NSInteger,HttpType) {
GET,
POST
};
static int timeOut = 30;
@interface HttpRequstData ()
{
NSString *_url;
NSDictionary *_parameters;
}
@property(nonatomic,strong)UILabel *tipsLable;
@end
@implementation HttpRequstData
+(void)getUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure
{
[[NetStatusData shareNetStatus] checkNetStatus];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval = timeOut;
// 加上这行代码,https ssl 验证。
if(openHttpsSSL)
{
[manager setSecurityPolicy:[self customSecurityPolicy]];
}
[MBProgressHUD showMessage:@"加载中..."];
DDLog(@"parameters:%@",parameters);
[manager GET:url parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
DDLog(@"====%@,%@==url:%@",responseObject,parameters,url);
[MBProgressHUD hideHUD];
//登陆成功===================================
if ([responseObject[@"status"] isEqualToNumber:@500]) {
[MBProgressHUD showSuccess:@"加载成功"];
if (success) {
success(responseObject);
}
}else{//登陆失败=============================
if ([responseObject[@"data"] isKindOfClass:[NSString class]]) {
[MBProgressHUD showError:responseObject[@"data"]];
}else{
[MBProgressHUD showError:@"信息错误"];
}
NSError *error1;
failure(error1);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// [[NetWorkingStausTipLabel shareNetWorkingStausTipLabel] showDuration:2.0];
[MBProgressHUD hideHUD];
[MBProgressHUD showError:@"网络异常"];
DDLog(@"%s==error--%@",__func__,error);
if (error) {
failure(error);
}
}];
}
+(void)getNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
[[NetStatusData shareNetStatus] checkNetStatus];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval = timeOut;
// 加上这行代码,https ssl 验证。
if(openHttpsSSL)
{
[manager setSecurityPolicy:[self customSecurityPolicy]];
}
DDLog(@"parameters:%@",parameters);
[manager GET:url parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
DDLog(@"====%@,%@==url:%@",responseObject,parameters,url);
[MBProgressHUD hideHUD];
//登陆成功===================================
if ([responseObject[@"status"] isEqualToNumber:@500]) {
if (success) {
success(responseObject);
}
}else{//登陆失败=============================
if ([responseObject[@"data"] isKindOfClass:[NSString class]]) {
[MBProgressHUD showError:responseObject[@"data"]];
}else{
[MBProgressHUD showError:@"信息错误"];
}
NSError *error1;
failure(error1);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// [[NetWorkingStausTipLabel shareNetWorkingStausTipLabel] showDuration:2.0];
DDLog(@"%s==error--%@",__func__,error);
[MBProgressHUD hideHUD];
[MBProgressHUD showError:@"网络异常"];
if (error) {
failure(error);
}
}];
}
#pragma mark-------封装请求
+(void)postUrl:(NSString*)url parameters:(NSDictionary*)parameters showHUD:(BOOL)show success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
[[NetStatusData shareNetStatus] checkNetStatus];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval = timeOut;
// 加上这行代码,https ssl 验证。
if(openHttpsSSL)
{
[manager setSecurityPolicy:[self customSecurityPolicy]];
}
if (show) {
[MBProgressHUD showMessage:@"加载中..."];
}
DDLog(@"parameters:%@==url:%@==",parameters,url);
[manager POST:url parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
DDLog(@"====%@,%@==url:%@===parameters:%@",responseObject,responseObject[@"data"],url,parameters);
if (show) {
[MBProgressHUD hideHUD];
}
//登陆成功===================================
if ([responseObject[@"status"] isEqualToNumber:@500]) {
if ([responseObject[@"data"] isKindOfClass:[NSArray class]]) {
if ([responseObject[@"data"] count] < 1) {
// [MBProgressHUD showSuccess:@"没有更多数据"];
}else{
if (show) {
// [MBProgressHUD showSuccess:@"加载成功"];
}
}
}else{
if (show) {
// [MBProgressHUD showSuccess:@"加载成功"];
}
}
if (success) {
success(responseObject);
}
}else{//登陆失败=============================
if ([responseObject[@"data"] isKindOfClass:[NSString class]]) {
// if (show) {
[MBProgressHUD showError:responseObject[@"data"]];
// }
}else{
// if (show) {
[MBProgressHUD showError:@"信息错误"];
// }
}
NSError *error1;
failure(error1);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// [[NetWorkingStausTipLabel shareNetWorkingStausTipLabel] showDuration:2.0];
if (show) {
[MBProgressHUD hideHUD];
}
// [MBProgressHUD showError:@"请求失败"];
DDLog(@"%s==error--%@",__func__,error);
if (error) {
failure(error);
}
}];
}
+(void)postUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure
{
[self postUrl:url parameters:parameters showHUD:YES success:success failure:failure];
}
+(void)postNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure
{
[self postUrl:url parameters:parameters showHUD:NO success:success failure:failure];
}
#pragma mark-------上传图片
+(NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(id)parameters constructingBodyWithBlock:(void (^)(id<AFMultipartFormData>))block progress:(void (^)(NSProgress *))uploadProgress success:(void (^)(NSURLSessionDataTask *, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError *))failure {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 加上这行代码,https ssl 验证。
if(openHttpsSSL)
{
[manager setSecurityPolicy:[self customSecurityPolicy]];
}
return [manager POST:URLString parameters:parameters constructingBodyWithBlock:block progress:uploadProgress success:success failure:failure];
}
+(NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(id)parameters constructingBodyWithBlock:(void (^)(id<AFMultipartFormData>))block success:(void (^)(NSURLSessionDataTask *, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError *))failure {
return [self POST:URLString parameters:parameters constructingBodyWithBlock:block progress:nil success:success failure:failure];
}
#pragma mark========https
+ (AFSecurityPolicy*)customSecurityPolicy
{
// /先导入证书
NSString *cerPath = [[NSBundle mainBundle] pathForResource:certificate ofType:@"cer"];//证书的路径
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
// AFSSLPinningModeCertificate 使用证书验证模式
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
// AFSSLPinningModeNone、AFSSLPinningModeCertificate
// allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
// 如果是需要验证自建证书,需要设置为YES
securityPolicy.allowInvalidCertificates = YES;
//validatesDomainName 是否需要验证域名,默认为YES;
//假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。
//置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。
//如置为NO,建议自己添加对应域名的校验逻辑。
securityPolicy.validatesDomainName = NO;
securityPolicy.pinnedCertificates = [[NSSet alloc] initWithObjects:certData,nil];
return securityPolicy;
}
2、封装网络状态监测
思路:用了一个单例,每次请求接口的时候调用小网络状态监测api
根据不同的网络情况显示提示
#import <Foundation/Foundation.h>
@interface NetStatusData : NSObject
@property(nonatomic,assign)AFNetworkReachabilityStatus status;//网络状态
+(NetStatusData*)shareNetStatus;
-(void)checkNetStatus;//检查网络状态
@end
static NetStatusData *_netStatus = nil;
@implementation NetStatusData
+(NetStatusData *)shareNetStatus {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!_netStatus) {
_netStatus = [NetStatusData new];
}
});
return _netStatus;
}
-(void)checkNetStatus {
AFNetworkReachabilityManager *manager=[AFNetworkReachabilityManager sharedManager];
__weak AFNetworkReachabilityManager *weakManager = manager;
[manager startMonitoring];
//检测网络状态有网络,网络请求数据,没网络提示
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
self.status = status;
if (!status) {//未连接
UIWindow *window = [[UIApplication sharedApplication].windows lastObject];
UILabel *tipsLable;
if (!tipsLable) {
tipsLable = [[UILabel alloc] initWithFrame:(CGRect){kScreenWidth/2,kScreenHeight/2+80,110,33}];
tipsLable.textColor = [UIColor whiteColor];
tipsLable.textAlignment = NSTextAlignmentCenter;
tipsLable.centerX = window.centerX;
tipsLable.backgroundColor = [UIColor blackColor];
tipsLable.text = @"网络未连接";
}
[window addSubview:tipsLable];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[tipsLable removeFromSuperview];
});
return;
}else{//连接请求数据
// [self requstData:type];
}
[weakManager stopMonitoring];
}];
}
@end
3、数据解析层(核心思想)
注:利用基类做类别封装请求,可以直接用模型请求接口,并且封装解析过程。根据不同的模型及json类型动态解析数据。后期代码免去解析代码
代码分为两部分,一部分代码解析,一部分数据请求
1、数据请求
#import <Foundation/Foundation.h>
@interface NSObject (Request)
//请求数据
+(void)requestUrl:(NSString*)url parameters:(NSDictionary*)parameters showHUD:(BOOL)show success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
+(void)requestUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
+(void)requestNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
//解析数据
+(id)parseData:(id)responseObject;
//对象转json
-(NSDictionary*)toJson;
//获取属性的类型
+(NSString*)getPropertyType:(NSString*)property;
-(NSString*)getPropertyType:(NSString*)property;
@end
#import "NSObject+Request.h"
#import <objc/runtime.h>
@implementation NSObject (Request)
+(void)requestUrl:(NSString*)url parameters:(NSDictionary*)parameters showHUD:(BOOL)show success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
[HttpRequstData postUrl:url parameters:parameters showHUD:show success:^(id responseObject) {
id obj = [self parseData:responseObject[@"data"]];
success(obj);
} failure:^(NSError *error) {
failure(error);
}];
}
+(void)requestUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
[self requestUrl:url parameters:parameters showHUD:YES success:success failure:failure];
}
+(void)requestNoHUDUrl:(NSString *)url parameters:(NSDictionary *)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure {
[self requestUrl:url parameters:parameters showHUD:NO success:success failure:failure];
}
+(id)parseData:(id)responseObject {
id obj;
//单个对象
if ([responseObject isKindOfClass:[NSDictionary class]]) {
obj = [[self alloc]init];
[obj setValuesForKeysWithDictionary:responseObject];
}
// 多个对象
else if ([responseObject isKindOfClass:[NSArray class]]) {
obj = [NSMutableArray new];
for (NSDictionary *dic in responseObject) {
id o = [[self alloc]init];
[o setValuesForKeysWithDictionary:dic];
[obj addObject:o];
}
}
return obj;
}
-(NSDictionary *)toJson
{
NSMutableDictionary *params = [NSMutableDictionary dictionary];
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(self.class, &count);
for (int i = 0; i < count; i++) {
const char *cname = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:cname];
NSString *key = [name substringFromIndex:1];
id value = [self valueForKey:key];
if ([value isKindOfClass:[NSString class]]&&[(NSString*)value length]) {
[params setValue:value forKey:key];
}
}
return params;
}
#pragma mark-------//获取属性的类型
+(NSString *)getPropertyType:(NSString *)property {
//获取对象的类型objc_getClass("UserModel")
objc_property_t p = class_getProperty(self, property.UTF8String);
if (!p) {
return nil;
}
const char *cname = property_getAttributes(p);
DDLog(@"%s==",cname);
// 2.成员类型
NSString *attrs = @(property_getAttributes(p));
NSUInteger dotLoc = [attrs rangeOfString:@","].location;
NSString *code = nil;
NSUInteger loc = 3;
if (dotLoc == NSNotFound) { // 没有,
code = [attrs substringFromIndex:loc];
} else {
code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc-1)];
}
DDLog(@"%@===%@====",code,attrs);
return code;
}
-(NSString *)getPropertyType:(NSString *)property {
//获取对象的类型objc_getClass("UserModel")
objc_property_t p = class_getProperty(self.class, property.UTF8String);
if (!p) {
return nil;
}
const char *cname = property_getAttributes(p);
DDLog(@"%s==",cname);
// 2.成员类型
NSString *attrs = @(property_getAttributes(p));
NSUInteger dotLoc = [attrs rangeOfString:@","].location;
NSString *code = nil;
NSUInteger loc = 3;
if (dotLoc == NSNotFound) { // 没有,
code = [attrs substringFromIndex:loc];
} else {
code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc-1)];
}
DDLog(@"%@===%@====",code,attrs);
return code;
}
@end
2、数据解析
思路:通过kvc解析数据,判断json的key值是否是json和数组是的话进一步解析。不是的话直接赋值,解决复杂类型的json动态解析。
注意:数据字段的时候需要指明数据放的对象类型
使用时需要解析的模型类需要继承Model类
/*
*对象中含有的模型数据对应的对象名称例如
*@{
@"statuses" : @"Status",===字段有statuses的数组含有的对象为Status类型
*};
*/
@property(nonatomic,strong)NSDictionary *classInArrayDic;
代码如下
#import <Foundation/Foundation.h>
#import "NSObject+Request.h"
@interface Model : NSObject<NSCoding,NSCopying>
//对象转json
-(NSDictionary*)toJson;
/*
*对象中含有的模型数据对应的对象名称例如
*@{
@"statuses" : @"Status",===字段有statuses的数组含有的对象为Status类型
*};
*/
@property(nonatomic,strong)NSDictionary *classInArrayDic;
@end
#import "Model.h"
@implementation Model
-(void)setValue:(id)value forKey:(NSString *)key{
if ([value isKindOfClass:[NSNumber class]]) {
[self setValue:[NSString stringWithFormat:@"%@",value] forKey:key];
}else if ([value isKindOfClass:[NSArray class]]) {
}else{
if (!value||[value isKindOfClass:[NSNull class]]) {
[super setValue:@"" forKey:key];
}else{
[super setValue:value forKey:key];
}
}
}
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
if ([key isEqualToString:@"description"]) {
[self setValue:value forKey:@"descriptionStr"];
}else if ([key isEqualToString:@"id"]){
[self setValue:value forKey:@"Id"];
}else if([key isEqualToString:@"newPrice"]){
[self setValue:value forKey:@"price"];
}else if([key isEqualToString:@"code"]){
[self setValue:value forKey:@"codePara"];
}else{
DDLog(@"没有key==%@",key);
}
}
-(void)setValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues {
for (NSString *key in keyedValues) {
id value = keyedValues[key];
//对象中含有对象数组
if ([value isKindOfClass:[NSArray class]]) {
if (![self.classInArrayDic objectForKey:key]) {
DDLog(@"请给数组对象对应类型");
continue;
}
//设置数组的值
NSMutableArray *values = [NSMutableArray new];
//取出数组含有对象类型
Class ObjectType = NSClassFromString(self.classInArrayDic[key]);
DDLog(@"%@",ObjectType);
for (NSDictionary *dic in value) {
//获取对象类型生成实例
id obj = [[ObjectType alloc]init];
[obj setValuesForKeysWithDictionary:dic];
[values addObject:obj];
}
[self setValue:values forKey:key];
}else if ([value isKindOfClass:[NSDictionary class]]) {//对象中含有对象
//获取对象的类型
NSString *type = [self getPropertyType:key];
if (type.length) {
DDLog(@"请给对象对应类型");
continue;
}
//获取对象类型生成实例
Class ObjectType = NSClassFromString(type);
id obj = [[ObjectType alloc]init];
[obj setValuesForKeysWithDictionary:value];
[self setValue:obj forKey:key];
}else {
[self setValue:value forKey:key];
}
}
}
-(NSDictionary *)toJson
{
NSMutableDictionary *params = [NSMutableDictionary dictionary];
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(self.class, &count);
for (int i = 0; i < count; i++) {
const char *cname = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:cname];
NSString *key = [name substringFromIndex:1];
id value = [self valueForKey:key];
if ([value isKindOfClass:[NSString class]]&&[(NSString*)value length]) {
[params setValue:value forKey:key];
}
}
return params;
}
#pragma mark-------NSCoding,归接档协议,运行时
- (void)encodeWithCoder:(NSCoder *)aCoder
{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(self.class, &count);
for (int i = 0; i < count; i++) {
const char *cname = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:cname];
NSString *key = [name substringFromIndex:1];
id value = [self valueForKey:key];
[aCoder encodeObject:value forKey:key];
}
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init]) {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(self.class, &count);
for (int i = 0; i < count; i++) {
const char *cname = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:cname];
NSString *key = [name substringFromIndex:1];
id value = [aDecoder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
}
return self;
}
-(id)copyWithZone:(NSZone *)zone {
id copy = [[[self class] allocWithZone:zone] init];
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(self.class, &count);
for (int i = 0; i < count; i++) {
const char *cname = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:cname];
NSString *key = [name substringFromIndex:1];
id value = [self valueForKey:key];
[copy setValue:value forKey:key];
}
return copy;
}
@end
网友评论