理解缓存访问 <- URL会话编程指南

URL加载系统为请求的响应提供内存与磁盘复合的缓存。该缓存允许应用程序减少对网络连接的依赖,并增加它的性能。

为请求使用缓存

NSURLRequest实例通过设置缓存策略来指定本地缓存的使用方式。缓存策略可以通过为NSURLRequestCachePolicy设置以下值来得到:NSURLRequestUseProtocolCachePolicy, NSURLRequestReloadIgnoringCacheData, NSURLRequestReturnCacheDataElseLoad, 或 NSURLRequestReturnCacheDataDontLoad.

NSURLRequest实例的默认缓存策略是NSURLRequestUseProtocolCachePolicy。NSURLRequestUseProtocolCachePolicy行为是特定于协议的,并且被定义为协议最合适的策略。

将缓存策略设置为NSURLRequestReloadIgnoringCacheData,会导致URL加载系统从原始资源加载数据,而忽略以完成的缓存。

NSURLRequestReturnCacheDataElseLoad缓存策略会导致URL加载系统使用缓存数据,却忽略这个缓存是否陈旧。当且仅当没有缓存数据时,URL加载系统会从原始资源处加载数据。

NSURLRequestReturnCacheDataDontLoad策略允许应用程序指定缓存可以返回的唯一数据。尝试使用缓存机制创建一个NSURLSessionTask实例,如果响应不是在本地缓存中,立即返回nil。这在功能上和“离线”模式类似,并且不产生网络连接。

注意:当前,只有对HTTP和HTTPS请求的响应才会被缓存。FTP和file协议尝试访问缓存策略允许的原始资源。自定义NSURLProtocol类可以选择性的提供缓存。

缓存使用HTTP协议语义

最复杂的缓存使用情况,是当请求使用HTTP协议,并且设置NSURLRequestUseProtocolCachePolicy为缓存策略。

如果请求没有NSCachedURLResponse,则URL加载系统会从原始资源获取数据。

如果请求存在缓存的响应,URL加载系统会检查该响应,以确定是否它所指定的内容必须要重新验证。

如果该内容需要重新验证,URL加载系统会制作原始资源的HEAD请求,用来查看该资源是否已经改变。如果它没有改变,URL加载系统就返回缓存的响应。如果它已经改变,URL加载系统会从原始资源处获取数据。

如果缓存的响应没有指定内容必须重新验证,URL加载系统检查指定缓存的响应的有效期。如果缓存的响应是近期的,则URL加载系统返回缓存的响应。如果响应过期了,URL加载系统会制作原始资源的HEAD请求,用来查看该资源是否已经改变。如果它没有改变,URL加载系统就返回缓存的响应。否则它会从原始资源处获取数据。

RFC 2616第13节(http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13
详细说明了涉及的语义。

以编码方式控制缓存

默认情况下,请求的数据会基于请求的缓存策略被缓存起来,由处理该请求的NSURLProtocol子类解读(interpreted)。

如果app需要对缓存进行更多精确的编程控制(如果该协议支持缓存),你可以实现委托方法,该方法允许app根据每个请求确定是否缓存特定的响应。

对于NSURLSession数据和上传任务,请实现URLSession:dataTask:willCacheResponse:completionHandler:方法。该委托方法只有在数据和上传任务的时候被调用。下载任务的缓存策略由特定的缓存策略决定。

对于NSURLSession,你的委托方法通过调用完成处理程序代码块告诉会话要缓存的内容。委托通常提供下列值中的一个:

  • 提供响应对象来允许缓存
  • 最新创见的响应对象来缓存修改的响应——例如,使用存储策略的响应允许缓存到内存而不是磁盘
  • nil用来防止缓存

你的委托方法还能向与NSCachedURLResponse对象相关的userInfo字典插入对象,从而将这些对象作为响应的一部分存储到缓存中。

重要:你的委托方法必须始终调用完成处理程序。否则,app会泄露内存。

代码清单5-1的示例阻止HTTPS响应的磁盘缓存。它还把当前日期添加到响应的缓存的用户信息字典中。

代码清单 5-1 URLSession:dataTask:willCacheResponse:completionHandler: 实现示例

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask

 willCacheResponse:(NSCachedURLResponse *)proposedResponse

 completionHandler:(void (^)(NSCachedURLResponse * __nullable cachedResponse))completionHandler {

    NSCachedURLResponse *newCachedResponse = proposedResponse;

    NSDictionary *newUserInfo;

    newUserInfo = [NSDictionary dictionaryWithObject:[NSDate date]

                                              forKey:@"Cached Date"];

    if ([proposedResponse.response.URL.scheme isEqualToString:@"https"]) {

#if ALLOW_IN_MEMORY_CACHING

        newCachedResponse = [[NSCachedURLResponse alloc]

                             initWithResponse:proposedResponse.response

                             data:proposedResponse.data

                             userInfo:newUserInfo

                             storagePolicy:NSURLCacheStorageAllowedInMemoryOnly];

#else // !ALLOW_IN_MEMORY_CACHING

        newCachedResponse = nil;

#endif // ALLOW_IN_MEMORY_CACHING

    } else {

        newCachedResponse = [[NSCachedURLResponse alloc]

                             initWithResponse:[proposedResponse response]

                             data:[proposedResponse data]

                             userInfo:newUserInfo

                             storagePolicy:[proposedResponse storagePolicy]];

    }

 

    completionHandler(newCachedResponse);

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,199评论 19 139
  • 概览 缓存组件应该说是每个客户端程序必备的核心组件,试想对于每个界面的访问都必须重新请求势必降低用户体验。但是如何...
    默默_David阅读 1,975评论 1 9
  • 本指南描述了Foundation框架的一些类,它们可用于与URL交互,也可以与使用标准网络协议的服务器进行通信。这...
    raingu24阅读 348评论 0 2
  • iOS网络编程读书笔记 Facade Tester客户端门面模式的实例(被动版本化) 被动版本化,所以硬编码URL...
    melouverrr阅读 1,656评论 3 7
  • 习惯是一种日常 坚持某件事也会渐渐的变成习惯 我说不出自己有那些习惯 但总会有某些事常常去做 别人问起,就会说,我...
    念时光z阅读 173评论 0 0