使用AFNetworking实现网络请求,同时集成YYCache实现缓存策略。
网络请求类WMNetwork.h
#import
typedef NS_ENUM(NSUInteger, WMClientRequestCachePolicy){
WMClientReturnCacheDataThenLoad = 0,///< 有缓存就先返回缓存,同步请求数据
WMClientReloadIgnoringLocalCacheData, ///< 忽略缓存,重新请求
WMClientReturnCacheDataElseLoad,///< 有缓存就用缓存,没有缓存就重新请求(用于数据不变时)
WMClientReturnCacheDataDontLoad,///< 有缓存就用缓存,没有缓存就不发请求,当做请求出错处理(用于离线模式)
};
typedef NS_ENUM(NSInteger,NetworkRequestType) {
NetworkGetType,
NetworkPostType
};
/* 请求数据Block */
typedef void (^WMBlock)(id responseObject,NSError *error);
/*刷新token*/
typedef void (^WMTokenBool)(BOOL ors);
@interface WMNetwork : NSObject
@property (nonatomic, assign) BOOL result;//是否需要重新请求数据
@property(nonatomic,copy)NSString *videoUploadProgress;//上传进度
###1.普通请求
- (void)requsetWithUrl:(NSString *)url withParams:(NSDictionary *)params withCacheType:(WMClientRequestCachePolicy)cacheType withRequestType:(NetworkRequestType)type withResult:(WMBlock)resultBlock;
###2.带访问权限的http请求 (Authorization)
- (void)requsetWithUrl:(NSString *)url withToken:(NSString *)headerstr withParams:(NSDictionary *)params withCacheType:(WMClientRequestCachePolicy)cacheType withRequestType:(NetworkRequestType)type withResult:(WMBlock)resultBlock;
//获取网络缓存的总大小 bytes(字节)
+ (NSInteger)getAllHttpCacheSize;
//刷新token
-(void)refreshTokens:(WMTokenBool)tokenbool;
//删除所有网络缓存
+ (void)removeAllHttpCache;
//上传头像
-(void)uploadPicturesWithUrl:(NSString*)url withToken:(NSString *)token withImage:(UIImage*)image withResult:(WMBlock)resultBlock;
//上传视频
- (void)uploadVideoWithUrl:(NSString *)url withToken:(NSString *)token withVideoData:(NSData *)videoData withVideoName:(NSString *)videoName withResult:(WMBlock)resultBlock;
@end
网络请求类WMNetwork.m
#import "WMNetwork.h"
#import "JSONKit.h"
#import "WMNetWorkCache.h"
@interface WMNetwork ()
@end
@implementation WMNetwork
#pragma mark- AFHTTPSessionManager单利
- (AFHTTPSessionManager *)managers{
static AFHTTPSessionManager *rmanager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
rmanager = [AFHTTPSessionManager manager];
NSString *userAgent = nil;
userAgent = [NSString stringWithFormat:@"XXXX/%@ (%@; %@; Apple; %@)",[[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion],[Platform iphoneType]];//[Platform iphoneType]判断手机类型
//设置自定义代理参数
NSString *language = [self getPreferredLanguage];
[rmanager.requestSerializer setValue:language forHTTPHeaderField:@"XXXXLanguage"];
[rmanager.requestSerializer setValue:userAgent forHTTPHeaderField:@"User-Agent"];
rmanager.responseSerializer = [AFJSONResponseSerializer serializer];
rmanager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"text/plain",@"image/jpg",nil];
// https 参数配置
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;
rmanager.securityPolicy = securityPolicy;
// 设置超时时间
[rmanager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
rmanager.requestSerializer.timeoutInterval = 60.f;
[rmanager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
//AF自动处理返回null对象的异常
AFJSONResponseSerializer *response = (AFJSONResponseSerializer *)rmanager.responseSerializer;
response.removesKeysWithNullValues = YES;
});
return rmanager;
}
- (NSString*)getPreferredLanguage {
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
NSArray * allLanguages = [defaults objectForKey:@"AppleLanguages"];
NSString * preferredLang = [allLanguages objectAtIndex:0];
return preferredLang;
}
###2.带访问权限的http请求 (Authorization)
- (void)requsetWithUrl:(NSString *)url withToken:(NSString *)headerstr withParams:(NSDictionary *)params withCacheType:(WMClientRequestCachePolicy)cacheType withRequestType:(NetworkRequestType)type withResult:(WMBlock)resultBlock{
[[self managers].requestSerializer setValue:headerstr forHTTPHeaderField:@"Authorization"];
[self requsetWithUrl:url withParams:params withCacheType:cacheType withRequestType:type withResult:resultBlock];
}
###1.普通请求
- (void)requsetWithUrl:(NSString *)url withParams:(NSDictionary *)params withCacheType:(WMClientRequestCachePolicy)cacheType withRequestType:(NetworkRequestType)type withResult:(WMBlock)resultBlock {
switch (type) {
case NetworkGetType:
{
// 响应缓存数据
[self getCache:cacheType url:url params:params withResult:resultBlock];
if (self.result) {
return;
}
[[self managers] GET:url parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (responseObject) {
[WMNetWorkCache setHttpCache:responseObject URL:url parameters:params];
}
[self handleRequestResultWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self handleRequestResultWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
}];
}
break;
case NetworkPostType:
{
// 响应缓存数据
[self getCache:cacheType url:url params:params withResult:resultBlock];
if (self.result) {
return;
}
[[self managers] POST:url parameters:params progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (responseObject) {
//对数据进行异步缓存
[WMNetWorkCache setHttpCache:responseObject URL:url parameters:params];
}
[self handleRequestResultWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self handleRequestResultWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
}];
}
break;
default:
break;
}
}
// 响应缓存
- (void)getCache:(WMClientRequestCachePolicy)cacheType url:(NSString *)url params:(NSDictionary *)params withResult:(WMBlock)resultBlock {
id object = [WMNetWorkCache httpCacheForURL:url parameters:params];
if (object) {
if (cacheType == WMClientReloadIgnoringLocalCacheData) {//忽略缓存,重新请求
self.result = NO;
} else if (cacheType == WMClientReturnCacheDataDontLoad) {//有缓存就用缓存,没有缓存就不发请求,当做请求出错处理(用于离线模式)
if (object) {
resultBlock(object,nil);
}
self.result = YES;
} else if (cacheType == WMClientReturnCacheDataElseLoad) {//有缓存就用缓存,没有缓存就重新请求(用于数据不变时)
if (object) {
resultBlock(object,nil);
}
self.result = YES;
} else if (cacheType == WMClientReturnCacheDataThenLoad) {///有缓存就先返回缓存,同步请求数据
if (object) {
resultBlock(object,nil);
}
self.result = NO;
}
}
}
// 数据回调
- (void)handleRequestResultWithDataTask:(NSURLSessionDataTask *)task responseObject:(id)responseObject error:(NSError *)error resultBlock:(WMBlock)resultBlock {
if(resultBlock) {
resultBlock(responseObject,error);
}
}
//获取网络缓存的总大小 bytes(字节)
+ (NSInteger)getAllHttpCacheSize{
return [WMNetWorkCache getAllHttpCacheSize];
}
//删除所有网络缓存,
+ (void)removeAllHttpCache{
[WMNetWorkCache removeAllHttpCache];
}
//上传视屏
- (void)uploadVideoWithUrl:(NSString *)url withToken:(NSString *)token withVideoData:(NSData *)videoData withVideoName:(NSString *)videoName withResult:(WMBlock)resultBlock {
[[self managers].requestSerializer setValue:token forHTTPHeaderField:@"Authorization"];
[[self managers] POST:url parameters:nil constructingBodyWithBlock:^(id _Nonnull formData) {
[formData appendPartWithFileData:videoData name:@"file" fileName:videoName mimeType:@"video/mp4"];
} progress:^(NSProgress * _Nonnull uploadProgress) {
self.videoUploadProgress = [NSString stringWithFormat:@"%.2f",1.0*uploadProgress.completedUnitCount/uploadProgress.totalUnitCount];
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[self handleRequestResultWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self handleRequestResultWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
}];
}
//上传图片
-(void)uploadPicturesWithUrl:(NSString*)url withToken:(NSString *)token withImage:(UIImage*)image withResult:(WMBlock)resultBlock{
[[self managers].requestSerializer setValue:token forHTTPHeaderField:@"Authorization"];
[[self managers] POST:url parameters:nil constructingBodyWithBlock:^(id _Nonnull formData) {
NSData *imageData = [self imageWithImage:image];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSString *fileName = [NSString stringWithFormat:@"%@.png",[formatter stringFromDate:[NSDate date]]];
[formData appendPartWithFileData:imageData name:@"file" fileName:fileName mimeType:@"image/png"];
} progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[self handleRequestResultWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self handleRequestResultWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
}];
}
//图片压缩
- (NSData *)imageWithImage:(UIImage*)newImage{
NSData *data=UIImageJPEGRepresentation(newImage, 1.0);
if (data.length>100*1024) {
if (data.length>1024*1024) {//1M以及以上
data=UIImageJPEGRepresentation(newImage, 0.1);
} else if (data.length>512*1024) {//0.5M-1M
data=UIImageJPEGRepresentation(newImage, 0.5);
} else if (data.length>200*1024) {//0.25M-0.5M
data=UIImageJPEGRepresentation(newImage, 0.9);
}
}
return data;
}
//刷新token
- (void)refreshTokens:(WMTokenBool)tokenbool {
NSString *tokens = [[NSUserDefaults standardUserDefaults] objectForKey:saveCompleteToken];
NSString *idfv = [[UIDevice currentDevice].identifierForVendor UUIDString];
NSString *islogin= [[[NSUserDefaults standardUserDefaults] objectForKey:saveUserData] objectForKey:@"id"];
NSString *urls = [NSString stringWithFormat:@"刷新token的url请求?device_uuid=%@&is_login=%@",idfv,islogin];
[self requsetWithUrl:urls withToken:tokens withParams:nil withCacheType:WMClientReloadIgnoringLocalCacheData withRequestType:NetworkGetType withResult:^(id responseObject, NSError *error) {
if (!error) {
if ([[responseObject objectForKey:@"code"] integerValue]==0) {
[[NSUserDefaults standardUserDefaults] setObject:OCSTR(@"Bearer %@",[[responseObject objectForKey:@"data"] objectForKey:@"refreshToken"]) forKey:saveCompleteToken];
tokenbool(YES);
} else {
tokenbool(NO);
}
} else {
tokenbool(NO);
}
}];
}
@end
缓存处理类(WMNetWorkCache.h)
#import
@interface WMNetWorkCache : NSObject
/**
* 缓存网络数据,根据请求的 URL与parameters
* 做KEY存储数据, 这样就能缓存多级页面的数据
*
* @param httpData 服务器返回的数据
* @param URL 请求URL地址
* @param parameters 请求参数
*/
+ (void)setHttpCache:(id)httpData URL:(NSString *)URL parameters:(NSDictionary *)parameters;
/**
* 根据请求的 URL与parameters 取出缓存数据
*
* @param URL 请求的URL
* @param parameters 请求的参数
*
* @return 缓存的服务器数据
*/
+ (id)httpCacheForURL:(NSString *)URL parameters:(NSDictionary *)parameters;
/**
* 获取网络缓存的总大小 bytes(字节)
*/
+ (NSInteger)getAllHttpCacheSize;
/**
* 删除所有网络缓存,
*/
+ (void)removeAllHttpCache;
@end
缓存处理类(WMNetWorkCache.m)
#import "WMNetWorkCache.h"
#import "YYCache.h"
@implementation WMNetWorkCache
static NSString *const NetworkResponseCache = @"NetworkResponseCache";
static YYCache *_dataCache;
+ (void)initialize {
_dataCache = [YYCache cacheWithName:NetworkResponseCache];
}
+ (void)setHttpCache:(id)httpData URL:(NSString *)URL parameters:(NSDictionary *)parameters {
NSString *cacheKey = [self cacheKeyWithURL:URL parameters:parameters];
//异步缓存,不会阻塞主线程
[_dataCache setObject:httpData forKey:cacheKey withBlock:nil];
}
+ (id)httpCacheForURL:(NSString *)URL parameters:(NSDictionary *)parameters {
NSString *cacheKey = [self cacheKeyWithURL:URL parameters:parameters];
return [_dataCache objectForKey:cacheKey];
}
+ (NSInteger)getAllHttpCacheSize {
return [_dataCache.diskCache totalCost];
}
+ (void)removeAllHttpCache {
[_dataCache.diskCache removeAllObjects];
}
+ (NSString *)cacheKeyWithURL:(NSString *)URL parameters:(NSDictionary *)parameters {
if(!parameters) {
return URL;
};
// 将参数字典转换成字符串
NSData *stringData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];
NSString *paraString = [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
// 将URL与转换好的参数字符串拼接在一起,成为最终存储的KEY值
NSString *cacheKey = [NSString stringWithFormat:@"%@%@",URL,paraString];
return cacheKey;
}
@end