在iOS app的开发过程当中,网络数据的缓存一直来讲都是一件常见,但又繁琐的任务,常常会有各类老大们提出这样那样的缓存要求。
通常而言缓存技术都无外乎如下几点。第一种则是使用系统内置的缓存处理机制,就如本文所提到的,包括了使用一些第三方库,也是使用系统底层内置的缓存。另一种则是使用额外的缓存工具,好比数据库、文件存储等进行保存,同时本身来控制缓存的策略。
缓存的方式不少,不管你选择使用哪种,我相信理解这些系统底层的处理机制对你最终选择本身的处理策略会颇有帮助。数据库
NSURLCache是iOS系统用于实现网络缓存的一个组件,被放于NSURL Loading这一个功能组件中。
在NSURLConnection加载系统中,缓存被设计为request对象的一个属性,由NSURLRequest对象的cachePolicy属性指定。而在NSURLSession加载系统中,缓存被设计为NSURLSessionConfiguration对像的一个属性,该属性所指定的策略被该session的全部request所共享。缓存
NSURLRequestUseProtocolCachePolicy是默认的缓存策略,它使用当前URL的协议中预置的缓存策略,不管这个协议是http,仍是说你本身定义协议。
对于咱们常见的http协议来讲,这个策略根据请求的头来执行缓存策略。服务器能够在返回的响应头中加入Expires策略或者Cache-Control策略来告诉客户端应该执行的缓存行为,同时配合#Last-Modified#等头来控制刷新的时机。
有关具体的http缓存策略这里不详述。服务器
NSURLRequestReloadIgnoringCacheData 这个策略则根本不会缓存数据网络
NSURLRequestReturnCacheDataElseLoad 这个策略比较有趣,它会一直偿试读取缓存数据,直到没法没有缓存数据的时候,才会去请求网络。这个策略有一个重大的缺陷致使它根本没法被使用,即它根本没有对缓存的刷新时机进行控制,若是你要去使用它,那么须要额外的进行对缓存过时进行控制。session
这个选项只读缓存,不管什么时候都不会进行网络请求。app
在默认的这几个选项之下,若是你须要对缓存进行精确的控制或者修改,则须要实现NSURLProtocol子类了工具
NSURLSession的数据和上传任务,能够实现URLSession:dataTask:willCacheResponse:completionHandler:
方法。另外,下载的任务在这里是不可用的。设计
对于NSURLConnection,则实现connection:willCacheResponse:
方法代理
NSURLSession提供一个block来告之会话须要缓存什么东西,而NSURLConnection代理则须要返回一个NSURLCachedResponse对象。
通常来讲,若是你须要修改须要缓存的内容,那么你须要新建立一个NSURLCachedResponse对象来被缓存,同时用于下一次的返回。另外返回nil则会阻止缓存行为。如:code
\- (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; }
在第一次请求到服务器资源的时候,服务器须要使用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 则由客户端发送,标识客户端所记录的,资源的最后修改时间。服务器接收到带有该请求头的请求时,会使用该时间与资源的最后修改时间进行对比,若是发现资源未被修改过,则直接返回HTTP 304而不返回包体,告诉客户端直接使用本地的缓存。不然响应完整的消息内容。
Etag 由服务器发送,告之当资源在服务器上的一个惟一标识符。客户端请求时,若是发现资源过时(使用Cache-Control的max-age),发现资源具备Etag声明,这时请求服务器时则带上If-None-Match头,服务器收到后则与资源的标识进行对比,决定返回200或者304。