1. NSURLCache简介:
iOS对NSURLRequest提供了7种缓存策略:(实际上能用的只有4种)
NSURLRequestUseProtocolCachePolicy // 默认的缓存策略(取决于协议)
NSURLRequestReloadIgnoringLocalCacheData // 忽略缓存,重新请求
NSURLRequestReloadIgnoringLocalAndRemoteCacheData // 未实现
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData // 忽略缓存,重新请求
NSURLRequestReturnCacheDataElseLoad// 有缓存就用缓存,没有缓存就重新请求
NSURLRequestReturnCacheDataDontLoad// 有缓存就用缓存,没有缓存就不发请求,当做请求出错处理(用于离线模式)
NSURLRequestReloadRevalidatingCacheData // 未实现
NSURLCache的常见用法
(1)获得全局缓存对象(没必要手动创建)NSURLCache *cache = [NSURLCache sharedURLCache];
(2)设置内存缓存的最大容量(字节为单位,默认为512KB)- (void)setMemoryCapacity:(NSUInteger)memoryCapacity;
(3)设置硬盘缓存的最大容量(字节为单位,默认为10M)- (void)setDiskCapacity:(NSUInteger)diskCapacity;
(4)硬盘缓存的位置:沙盒/Library/Caches
(5)取得某个请求的缓存- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request;
(6)清除某个请求的缓存- (void)removeCachedResponseForRequest:(NSURLRequest *)request;
(7)清除所有的缓存- (void)removeAllCachedResponses;
缓存GET请求
要想对某个GET请求进行数据缓存,非常简单
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置缓存策略
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
只要设置了缓存策略,系统会自动利用NSURLCache进行数据缓存
缓存的注意事项
缓存的设置需要根据具体的情况考虑,如果请求某个URL的返回数据:
(1)经常更新:不能用缓存!比如股票、彩票数据
(2)一成不变:果断用缓存
(3)偶尔更新:可以定期更改缓存策略 或者 清除缓存
提示:如果大量使用缓存,会越积越大,建议定期清除缓存
2.借助ETag或Last-Modified判断文件缓存是否有效
通过打印一个response实例,可以看到response header部分如下所示:
我们可以在请求数据时先上传Etag或者是Last-Modified让服务器端进行判断,若数据未发生变动则加载本地数据,否则加载服务器端数据。
请求的HeaderValue和响应的HeaderValue如下所示:
下面以Etag为例进行数据缓存:
先设置缓存内存和硬盘大小:
NSURLCache *urlCache= [[NSURLCache alloc]initWithMemoryCapacity:4*1024*1024 diskCapacity:20*1024*1024 diskPath:nil]; [NSURLCache setSharedURLCache:urlCache];
下载一张图片:
- (IBAction)download:(UIButton *)sender { NSURL *url=[NSURL URLWithString:@"http://192.168.1.102:8080/love/images/bg2.jpg"]; NSMutableURLRequest *mRequest=[NSMutableURLRequest requestWithURL:url]; mRequest.cachePolicy=NSURLRequestReloadIgnoringCacheData; mRequest.timeoutInterval=5; // 根据请求获取到`被缓存的响应`! NSCachedURLResponse *cacheResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:mRequest]; //cacheResponse不存在时设置etag为空 if (!cacheResponse) { self.etag=nil; } //发送etag if (self.etag.length>0) { //NSLog(@"Etag=%@",self.etag); [mRequest setValue:self.etag forHTTPHeaderField:@"If-None-Match"]; } [NSURLConnection sendAsynchronousRequest:mRequest queue:[NSOperationQueue new] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { // 类型转换(如果将父类设置给子类,需要强制转换) NSHTTPURLResponse *httpResponse=(NSHTTPURLResponse*)response; // NSLog(@"res=%@",httpResponse); // 判断响应的状态码是否是 304 Not Modified (更多状态码含义解释: https://github.com/ChenYilong/iOSDevelopmentTips) if (httpResponse.statusCode==304) { NSLog(@"加载本地缓存图片"); // 如果是,使用本地缓存 // 根据请求获取到`被缓存的响应`! NSCachedURLResponse *cacheResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:mRequest]; // 拿到缓存的数据 data = cacheResponse.data; }else{ NSLog(@"请求网络端图片"); } if(data){ [self performSelectorOnMainThread:@selector(setImage:) withObject:data waitUntilDone:YES]; } self.etag=httpResponse.allHeaderFields[@"Etag"]; }]; // NSArray *arr=NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES); // NSString *path=[arr objectAtIndex:0]; // NSLog(@"%@",path); } -(void)setImage:(NSData*)data{ // NSLog(@"setimage"); self.imageView.image=[UIImage imageWithData:data]; }
清除所有缓存:
- (IBAction)clearCache:(UIButton *)sender {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
参考文献: