一、需求
1.在IOS应用程序开发中,为了减少与服务端的交互次数,加快用户的响应速度,一般都会在IOS设备中加一个缓存的机制。使用缓存的目的是为了使用的应用程序能更快速的响应用户输入,是程序高效的运行。有时候我们需要将远程web服务器获取的数据缓存起来,减少对同一个url多次请求。使用sdk中的NSURLCache类,可以很方便的实现此功能。
2.NSURLCache可以做到完全的离线缓存,即在没有网络的情况下打开离线内容。通过自定义的实现,将缓存文件存放到沙盒路径下,缓存空间没有大小限制。可以借鉴H5离线缓存中的Manifest文件,来定义缓存策略。Manifest文件从服务器端下载下来,在本地做版本对比,来实现存储和更新。
3. NSURLCache拦截不到WKWebView中发出的任何网络请求。所以如果使用WKWebView的话,NSURLCache实现不了离线缓存的功能。
二、一般使用场景
1.NSURLRequest需要一个缓存策略参数来说明它请求的url何如缓存数据的:CachePolicy类型。
(1)NSURLRequestUseProtocolCachePolicy:NSURLRequest默认的cache policy,使用Protocol协议定义。
(2)NSURLRequestReloadIgnoringCacheData:忽略缓存直接从原始地址下载。
(3)NSURLRequestReturnCacheDataElseLoad:只有在cache中不存在data时才从原始地址下载。
(4)NSURLRequestReturnCacheDataDontLoad:只使用cache数据,如果不存在cache,请求失败;用于没有建立网络连接离线模式;
(5)NSURLRequestReloadIgnoringLocalAndRemoteCacheData:忽略本地和远程的缓存数据,直接从原始地址下载,与NSURLRequestReloadIgnoringCacheData类似。
(6)NSURLRequestReloadRevalidatingCacheData:验证本地数据与远程数据是否相同,如果不同则下载远程数据,否则使用本地数据。
(7)说明:5和6苹果暂未实现。
2.首先我们需要在发送请求之前设置一下缓存大小:
(1)默认情况下,内存是4M,4* 1024 * 1024;硬盘为20M,20 * 1024 * 1024;
[[NSURLCache sharedURLCache] setMemoryCapacity:4*1024*1024]。
[[NSURLCache sharedURLCache] setDiskCapacity:20*1024*1024]。
(2)也可以自己初始化缓存对象:
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4*1024*1024 diskCapacity:20*1024*1024 diskPath:path];
[NSURLCache setSharedURLCache:URLCache];
3.控制需不需要缓存:
NSURLConnectionDataDelegate代理方法中,下面的方法用来指定此次请求需不需要缓存,同时也可以在返回之前,修改response里面的数据:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
三、要点:
1.UIWebView的的NSURLRequest请求,以及自己用NSURLConnection发送的请求,NSURLCache都会拦截并存储。
2.NSURLCache只对异步请求有效。
3.NSURLCache的缓存包括内存缓存和磁盘缓存,iOS4.x系统只有内存缓存,iOS5.x及以上两者都有,但仅支持HTTP,HTTPS在iOS6中增加了支持。磁盘缓存有默认的缓存路径,也可以自己指定路径。
4.当系统存储空间不足时,当前的请求不会被缓存,包括之前的磁盘缓存也可能被系统清除掉。
5.如果有使用NSURLCache,在应用收到内存警告时,应该清空缓存:removeAllCachedResponses。
四:NSURLCache相关API:
1.功能方法:
(1)- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request;
返回对应的NSURLRequest缓存的response,如果没有则返回nil。
(2)- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request;
为特定的NSURLRequest指定缓存对象,并存储。
(3)- (void)removeCachedResponseForRequest:(NSURLRequest *)request;
移除特定NSURLRequest的cache。
(4)- (void)removeAllCachedResponses;
移除所有的cache。
2.property方法
- (NSUInteger)memoryCapacity;
- (NSUInteger)diskCapacity;
- (void)setMemoryCapacity:(NSUInteger)memoryCapacity;
- (void)setDiskCapacity:(NSUInteger)diskCapacity;
- (NSUInteger)currentMemoryUsage;
- (NSUInteger)currentDiskUsage;
五、NSCachedURLResponse对象:包装了一下系统缓存机制的对象,保持了缓存对象的个性和特性。
1. NSURLCacheStoragePolicy 缓存策略有三种
enum
{
NSURLCacheStorageAllowed,
NSURLCacheStorageAllowedInMemoryOnly,
NSURLCacheStorageNotAllowed,
};
2. 构造方法
- (id)initWithResponse:(NSURLResponse *)response data:(NSData *)data;
- (id)initWithResponse:(NSURLResponse *)response data:(NSData *)data userInfo:(NSDictionary *)userInfo storagePolicy:(NSURLCacheStoragePolicy)storagePolicy;
3. 相关API
- (NSURLResponse *)response;
- (NSData *)data;
- (NSDictionary *)userInfo;
- (NSURLCacheStoragePolicy)storagePolicy;
六、自定义NSURLCache
在一些特殊场景,如果要实现自定义的缓存机制,需要子类化NSURLCache。
1.重写cachedResponseForRequest:(NSURLRequest *)request,这个会在请求发送前会被调用,从中我们可以判定是否针对此NSURLRequest返回本地数据。如果本地没有缓存就调用下面这条语句:return [super cachedResponseForRequest:request];
2.重写storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request,我们可以对某一个请求做我们自己的数据保存机制,如果使用系统默认的数据保存机制,则调用[super storeCachedResponse:cachedResponse forRequest:request];
七、自定义NSURLCache简单示例:
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request{
//获取URL整体路径
NSString *urlStringMD5 = [self md5:request.URL.absoluteString];
//获取缓存文件存储地址
NSString *filePath = [[self getDocumentPath] stringByAppendingPathComponent:urlStringMD5];
//如果缓存存在,则返回缓存数据,否则使用系统默认处理
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
//获取缓存文件路径
NSData *fileData = [[NSData alloc] initWithContentsOfFile:filePath];
//根据URL路径,获取媒体类型
NSString *memiType = [self mimeTypeForPath:request.URL.absoluteString];
//合成NSCachedURLResponse对象,返回
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[request URL]
MIMEType:memiType
expectedContentLength:[fileData length]
textEncodingName:nil];
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:fileData];
return cachedResponse;
}else{
return [super cachedResponseForRequest:request];
}
}
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request{
//将服务器返回数据缓存起来
NSString *urlStringMD5 = [self md5:request.URL.absoluteString];
NSString *filePath = [[self getDocumentPath] stringByAppendingPathComponent:urlStringMD5];
[cachedResponse.data writeToFile:filePath atomically:YES];
}