iOS GET缓存的实现

前言叨逼叨


  • HS的1.5版本多灾多难,被SBPM蹂躏一番之后还是如期上线了,最近先下重新看以前网络的基础资料,进行知识储备,现在总结一些零落的知识点。
  • 书归正传,以前常听说get 请求是可以缓存的,但是一直不知道具体含义,今天具体讲解一下get的缓存,以及具体的代码实现

苹果提供缓存策略


首先我们了解一下苹果提供了那些缓存策略

  • NSURLRequestUseProtocolCachePolicy = 0, 默认的缓存策略, 如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断下一步操作,如: Cache-Control字段为must-revalidata, 则询问服务端该数据是否有更新,无更新的话直接返回给用户缓存数据,若已更新,则请求服务端.

  • NSURLRequestReloadIgnoringLocalCacheData = 1, 忽略本地缓存数据,直接请求服务端.

  • NSURLRequestIgnoringLocalAndRemoteCacheData = 4, 忽略本地缓存,代理服务器以及其他中介,直接请求源服务端.

  • NSURLRequestReloadIgnoringCacheData 略本地和远程的缓存数据,直接从原始地址下载,从API中可以看出是和NSURLRequestReloadIgnoringCacheData一样的。

  • NSURLRequestReturnCacheDataElseLoad = 2, 有缓存就使用,不管其有效性(即忽略Cache-Control字段), 无则请求服务端.

  • NSURLRequestReturnCacheDataDontLoad = 3, 死活加载本地缓存. 没有就失败. (确定当前无网络时使用)

  • NSURLRequestReloadRevalidatingCacheData = 5, 缓存数据必须得得到服务端确认有效才使用(貌似是NSURLRequestUseProtocolCachePolicy中的一种情况)

具体讲解


  • 在web开发或者客户端开发大多数网络请求中(下载之类的除外),缓存一般都是不利的,使我们对数据的准确性的判断造成问题,故,我们在基本的网络访问的时候,通常忽略本地缓存,下面的代码演练中我们也是采取这样的原则,将缓存策略定为1
NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:self.url cachePolicy:1 timeoutInterval:10];

在请求头中,有一个键值是 If-None-Match,响应头里有一个键值是Etag,所以基本思路时,在一次请求结束以后,我们将响应头中的Etag记录,在下次发起请求的时候,将其设置给请求头中的If-None-Match,即将本地的缓存与服务器返回的内容进行对比,如果responsestatusCode为304,表明服务器和本地缓存一直,没发生变化

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSURL *url = [NSURL URLWithString:@"http://localhost/itcast/images/head1.png"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:10.0];

    if (self.etag.length > 0) {
        NSLog(@"%@", self.etag);

        [request setValue:self.etag forHTTPHeaderField:@"If-None-Match"];
    }

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        NSLog(@"%@", httpResponse);

        // 判断服务器返回的状态码,是否是 304
        if (httpResponse.statusCode == 304) {
            NSLog(@"加载缓存数据");

            NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
            data = cachedResponse.data;
        }

        self.etag = httpResponse.allHeaderFields[@"Etag"];
        self.iconView.image = [UIImage imageWithData:data];
    }];
}

全局缓存区设置

NSURLCache *urlCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil];
[NSURLCache setSharedURLCache:urlCache];

简单的小结一下

  • 请求的缓存策略使用 NSURLRequestReloadIgnoringCacheData,忽略本地缓存
  • 服务器响应结束后,要记录 Etag,服务器内容和本地缓存对比是否变化的重要依据
  • 在发送请求时,设置 If-None-Match,并且传入 Etag
  • 连接结束后,要判断响应头的状态码,如果是 304,说明本地缓存内容没有发生变化

后续

  • GET 缓存的数据会保存在 Cache 目录中 \bundleId 下 Cache.db 中
    • cfurl_cache_receiver_data,缓存所有的请求数据
    • cfurl_cache_response,缓存所有的响应
      可以用过SQLite去查看,后续文字可能会更新
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容