NSURLSession 是iOS7之后对 NSURLConnection 更进一步的优化封装,可通过 NSURLSessionConfiguration 对其进行初始化设置,其中 requestCachePolicy 属性设置就是配置获取得到 NSURLResponse 之后的缓存策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy) { NSURLRequestUseProtocolCachePolicy = 0, NSURLRequestReloadIgnoringLocalCacheData = 1, NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData, NSURLRequestReturnCacheDataElseLoad = 2, NSURLRequestReturnCacheDataDontLoad = 3, NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, NSURLRequestReloadRevalidatingCacheData = 5, };
|
关于 AFNetWorking 的缓存
其实 AFNetWorking(特指3.x版本)本质上讲就是基于对 NSURLSession 的再一次封装,所以它默认就已经可以使用 NSURLCache 缓存,即我们可以直接使用 NSURLCache 进行缓存设置,而 NSURLCache 是一个 NSURLRequest 对应一个 NSURLResponse 进行缓存的。
1
| - (nullable NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request;
|
我们正常的使用 AFN 进行 get 请求如下:
1 2 3 4 5 6 7
| AFHTTPSessionManager *manager = [self setupAFHTTPSessionManager]; NSURLSessionDataTask *task = [manager GET:self.requestUrl parameters:self.parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { handler(responseObject, nil); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { handler(nil, error); }];
|
然后 get 方法创建完成后会返回一个 NSURLSessionDataTask 对象,我们通过 task.originalRequest 即可获取上一次的 NSURLRequest 对象,通过它我们即可以从 cache 中获取缓存数据。
1 2 3 4 5 6
| NSCachedURLResponse *reaponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:a.originalRequest]; if (reaponse) { handler(reaponse.data, nil); [task cancel]; }
|
但是我们在第一进行请求的时候肯定是没有缓存的,所以在第一次缓存成功后需要对返回的 NSURLResponse 对象进行缓存:
1 2 3
| NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:0 error:nil]; NSCachedURLResponse * cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:task.response data:data]; [[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:task.originalRequest];
|
封装我们自己的 NSCache
主要最对缓存数据进行过期处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| @interface BHCustomURLCache : NSURLCache
+ (instancetype)standardURLCache;
@end
#import "BHCustomURLCache.h"
static NSString * const CustomURLCacheExpirationKey = @"CustomURLCacheExpiration"; static NSTimeInterval const CustomURLCacheExpirationInterval = 600;
@interface BHCustomURLCache()
@end
@implementation BHCustomURLCache
+ (instancetype)standardURLCache { static BHCustomURLCache *_standardURLCache = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _standardURLCache = [[BHCustomURLCache alloc] initWithMemoryCapacity:(2 * 1024 * 1024) diskCapacity:(100 * 1024 * 1024) diskPath:nil]; }); return _standardURLCache; } #pragma mark - NSURLCache - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request { NSCachedURLResponse *cachedResponse = [super cachedResponseForRequest:request]; if (cachedResponse) { NSDate* cacheDate = cachedResponse.userInfo[CustomURLCacheExpirationKey]; NSDate* cacheExpirationDate = [cacheDate dateByAddingTimeInterval:CustomURLCacheExpirationInterval]; if ([cacheExpirationDate compare:[NSDate date]] == NSOrderedAscending) { [self removeCachedResponseForRequest:request]; return nil; } } return cachedResponse; }
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request { NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:cachedResponse.userInfo]; userInfo[CustomURLCacheExpirationKey] = [NSDate date]; NSCachedURLResponse *modifiedCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy]; [super storeCachedResponse:modifiedCachedResponse forRequest:request]; }
@end
|
最后
关于实际开发中,接口数据可能需要实时获取最新的数据,这就要需要我们自己修改接口数据刷新策略,一种常见的做法,每次接口请求的时候都带上上次请求的时间戳,当服务端有新数据返回时即解析最新的数据,重新加入缓存;当没有新数据时则可以通过返回状态码302的方式通知客户端直接获取缓存数据。
代码可以下载GITHUB中BlogDemo进行查看。