#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, WACachePolicy) {
WAURLRequestReturnCacheDataElseLoad,//有缓存就用缓存,没有缓存就重新请求
WAURLRequestReturnLocalAndRemoteCacheData,//先返回本地数据,然后返回网络数据
WAURLRequestReloadIgnoringLocalAndRemoteCacheData //直接请求网络数据
};
@interface WARequest : NSObject
+ (void)requestWithUrl:(NSString *)url params:(NSDictionary *)params cachePolicy:(WACachePolicy)cachePolicy cacheTime:(NSInteger)cacheTime completeBlock:(void(^)(NSDictionary *result))completeBlock;
@end
//
// WARequest.m
// test
//
// Created by yfxiari on 2018/2/5.
// Copyright © 2018年 xxx. All rights reserved.
//
#import "WARequest.h"
#import <CommonCrypto/CommonCrypto.h>
@implementation WARequest
/**
缓存类型:
1.本地有缓存,加载本地缓存,如果没过期,不用加载最新的数据;如果过期了,则请求最新的数据,并缓存。
2.本地有缓存先加载本地缓存,然后请求网络数据,再更新缓存
3.不加载缓存,直接请求网络数据。
*/
/**
策略2其实还是有问题的,因为如果回调了两遍,如果是分页的话,第二页就有问题了,因为加载第二页数据会重复加载。
所以:如果是预加载缓存缓存还是写在页面基类中比较好,网络封装缓存应使用只加载缓存或只请求网络数据两者策略。
但是:如果缓存用的是数据库,用id和size来分页,则就可以使用网络封装来实现预加载功能。
*/
+ (void)requestWithUrl:(NSString *)url params:(NSDictionary *)params cachePolicy:(WACachePolicy)cachePolicy cacheTime:(NSInteger)cacheTime completeBlock:(void(^)(NSDictionary *result))completeBlock {
[self clearCache];
// 用混存数据
if (cachePolicy == WAURLRequestReturnCacheDataElseLoad) {
NSDictionary *dict = [self getCacheUrl:url params:params cacheTime:cacheTime];
BOOL valid = [self checkCacheUrl:url params:params cacheTime:cacheTime];
if (dict) {
completeBlock(dict);
if (valid) {
return;
}
}
}
if (cachePolicy == WAURLRequestReturnLocalAndRemoteCacheData) {
NSDictionary *dict = [self getCacheUrl:url params:params cacheTime:cacheTime];
if (dict) {
completeBlock(dict);
}
}
NSString *allUrl = [self urlStringWithUrl:url params:params];
// 请求去了
NSDictionary *headers = @{ @"Cache-Control": @"no-cache",
@"Postman-Token": @"0f97d71d-a97a-be5b-15d8-7276d645eb26" };
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:allUrl]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
} else {
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
if (result) {
completeBlock(result);
if (cachePolicy != WAURLRequestReloadIgnoringLocalAndRemoteCacheData) {
[self cacheUrl:url params:params data:result];
}
}
}
}];
[dataTask resume];
}
+ (void)cacheUrl:(NSString *)url params:(NSDictionary *)params data:(NSDictionary *)dict {
NSString *file = [self filePathWithUrl:url params:params];
BOOL writed = [dict writeToFile:file atomically:YES];
NSString *log = writed ? @"写入成功":@"写入失败";
NSLog(@"%@", log);
}
+ (NSString *)filePathWithUrl:(NSString *)url params:(NSDictionary *)params {
NSString *cache_path = [self cachePath];
NSString *fileString = [self urlStringWithUrl:url params:params];
NSString *file = [self getMd5WithString:fileString];
NSString *path = [cache_path stringByAppendingPathComponent:file];
return path;
}
+ (NSDictionary *)getCacheUrl:(NSString *)url params:(NSDictionary *)params cacheTime:(NSInteger)cacheTime{
NSString *file = [self filePathWithUrl:url params:params];
return [NSDictionary dictionaryWithContentsOfFile:file];
return @{};
}
// 是否过期
+ (BOOL)checkCacheUrl:(NSString *)url params:(NSDictionary *)params cacheTime:(NSInteger)cacheTime {
NSString *file = [self filePathWithUrl:url params:params];
NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:file error:nil];
NSDate *modifiedDate = [attr objectForKey:NSFileModificationDate];
NSTimeInterval time = [[NSDate date] timeIntervalSinceDate:modifiedDate];
if (time > cacheTime) {
return NO;
}
return YES;
}
+ (NSString *)cachePath {
NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
return path;
}
+ (NSString *)urlStringWithUrl:(NSString *)url params:(NSDictionary *)params {
NSArray *sortArray = [params.allKeys sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1 compare:obj2];
}];
NSString *paramsString = @"";
for (NSString *key in sortArray) {
NSString *valueString = [NSString stringWithFormat:@"%@=%@&", key, params[key]];
paramsString = [paramsString stringByAppendingString:valueString];
}
NSString *allUrl = url;
if ([allUrl containsString:@"?"]) {
allUrl =[allUrl stringByAppendingString:paramsString];
}else {
allUrl = [allUrl stringByAppendingString:@"?"
];
allUrl =[allUrl stringByAppendingString:paramsString];
}
NSLog(@"%@", allUrl);
return allUrl;
}
+ (NSString *)urlKeyMd5StringWithUrl:(NSString *)url {
return [self getMd5WithString:url];
}
+ (NSString *)getMd5WithString:(NSString *)string {
const char *data = [string UTF8String];
//2: 初始化一个字符串数组,用来存放MD5加密后的数据
unsigned char resultArray[CC_MD5_DIGEST_LENGTH];
CC_MD5(data, (CC_LONG) strlen(data), resultArray);
//4: 初始化一个保存结果的字符串
NSMutableString *resultString = [NSMutableString string];
//5: 从保存结果的数组中,取出值赋给字符串
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[resultString appendFormat:@"%02X", resultArray[i]];
}
//6: 返回结果
return resultString;
}
+ (void)clearCache {
// 判断缓存大小
// 删除过期缓存
[self clearExpiredFile];
}
// 获取文件大小
- (float) folderSizeAtPath:(NSString *)folderPath{
NSFileManager * manager = [NSFileManager defaultManager];
if (![manager fileExistsAtPath :folderPath]) return 0 ;
NSEnumerator *childFilesEnumerator = [[manager subpathsAtPath :folderPath] objectEnumerator];
NSString * fileName;
long long folderSize = 0 ;
while ((fileName = [childFilesEnumerator nextObject]) != nil ){
//获取文件全路径
NSString * fileAbsolutePath = [folderPath stringByAppendingPathComponent :fileName];
folderSize += [self fileSizeAtPath:fileAbsolutePath];
}
return folderSize/( 1024.0 * 1024.0);
}
- (long long)fileSizeAtPath:(NSString *)filePath{
NSFileManager * manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath :filePath]){
return [[manager attributesOfItemAtPath :filePath error : nil] fileSize];
}
return 0;
}
/**
* 清空过期的日志
*/
+ (void)clearExpiredFile{
}
@end