为什么要理解NSURLCache?
在iOS app的开发过程中,网络数据的缓存一直来说都是一件常见,但又繁琐的任务,经常会有各种老大们提出这样那样的缓存要求。
一般而言缓存技术都无外乎以下几点。第一种则是使用系统内置的缓存处理机制,就如本文所提到的,包括了使用一些第三方库,也是使用系统底层内置的缓存。另外一种则是使用额外的缓存工具,比如数据库、文件存储等进行保存,同时自己来控制缓存的策略。
缓存的方式很多,无论你选择使用哪一种,我相信理解这些系统底层的处理机制对你最终选择自己的处理策略会很有帮助。
NSURLCache
NSURLCache是iOS系统用于实现网络缓存的一个组件,被放于NSURL Loading这一个功能组件中。
在NSURLConnection加载系统中,缓存被设计为request对象的一个属性,由NSURLRequest对象的cachePolicy属性指定。而在NSURLSession加载系统中,缓存被设计为NSURLSessionConfiguration对像的一个属性,该属性所指定的策略被该session的所有request所共享。
可选的缓存策略
NSURLRequestUseProtocolCachePolicy
NSURLRequestUseProtocolCachePolicy是默认的缓存策略,它使用当前URL的协议中预置的缓存策略,无论这个协议是http,还是说你自己定义协议。
对于我们常见的http协议来说,这个策略根据请求的头来执行缓存策略。服务器可以在返回的响应头中加入Expires策略或者Cache-Control策略来告诉客户端应该执行的缓存行为,同时配合#Last-Modified#等头来控制刷新的时机。
有关具体的http缓存策略这里不详述。
NSURLRequestReloadIgnoringCacheData
NSURLRequestReloadIgnoringCacheData 这个策略则根本不会缓存数据
NSURLRequestReturnCacheDataElseLoad
NSURLRequestReturnCacheDataElseLoad 这个策略比较有趣,它会一直偿试读取缓存数据,直到无法没有缓存数据的时候,才会去请求网络。这个策略有一个重大的缺陷导致它根本无法被使用,即它根本没有对缓存的刷新时机进行控制,如果你要去使用它,那么需要额外的进行对缓存过期进行控制。
NSURLRequestReturnCacheDataDontLoad
这个选项只读缓存,无论何时都不会进行网络请求。
精确的缓存控制
在默认的这几个选项之下,如果你需要对缓存进行精确的控制或者修改,则需要实现NSURLProtocol子类了
NSURLSession的数据和上传任务,可以实现
URLSession:dataTask:willCacheResponse:completionHandler:
方法。另外,下载的任务在这里是不可用的。对于NSURLConnection,则实现
connection:willCacheResponse:
方法
NSURLSession提供一个block来告之会话需要缓存什么东西,而NSURLConnection代理则需要返回一个NSURLCachedResponse对象。
一般来说,如果你需要修改需要缓存的内容,那么你需要新创建一个NSURLCachedResponse对象来被缓存,同时用于下一次的返回。另外返回nil则会阻止缓存行为。如:
\- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy];
NSMutableData *mutableData = [[cachedResponse data] mutableCopy];
NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly;
// ...
return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]
data:mutableData
userInfo:mutableUserInfo
storagePolicy:storagePolicy];
}
或者
\- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
与HTTP服务器进行交互的简单说明
Cache-Control头
在第一次请求到服务器资源的时候,服务器需要使用Cache-Control这个响应头来指定缓存策略,它的格式如下:Cache-Control:max-age=xxxx
,这个头指指明缓存过期的时间
Cache-Control头具有如下选项:
public: 指示可被任何区缓存
private
no-cache: 指定该响应消息不能被缓存
no-store: 指定不应该缓存
max-age: 指定过期时间
min-fresh:
max-stable:
Last-Modified/If-Modified-Since
Last-Modified 是由服务器返回响应头,标识资源的最后修改时间.
If-Modified-Since 则由客户端发送,标识客户端所记录的,资源的最后修改时间。服务器接收到带有该请求头的请求时,会使用该时间与资源的最后修改时间进行对比,如果发现资源未被修改过,则直接返回HTTP 304而不返回包体,告诉客户端直接使用本地的缓存。否则响应完整的消息内容。
Etag/If-None-Match
Etag 由服务器发送,告之当资源在服务器上的一个唯一标识符。
客户端请求时,如果发现资源过期(使用Cache-Control的max-age),发现资源具有Etag声明,这时请求服务器时则带上If-None-Match头,服务器收到后则与资源的标识进行对比,决定返回200或者304。