美文网首页iOS点点滴滴iOS Developer
使用NSURLCache做AFN和NSURLSession的缓存

使用NSURLCache做AFN和NSURLSession的缓存

作者: mkvege | 来源:发表于2017-10-23 08:00 被阅读93次
    图片源于网络

    最近使用NSUrlCache做网络缓存,感觉比之前自己建立数据库来缓存这些数据要简单的多,自己建立的数据库机制十分简陋,而是用系统提供的NSUrlCache 则更全面而稳定。我们不用费心去管理内存过大导致崩溃,也不用去管设置了固定容量之后新的返回值不能被缓存。

    值得注意的是只有get 方法才会产生缓存,而post方法不会产生缓存,但是这个几乎没有什么影响,因为post的方法多用于上传,和修改等接口,没有缓存的必要。

    使用这个方法可以整体设置 内存容量和硬盘容量以及存储位置。

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

    这段代码可以放到AppDelegate中,在程序启动时就设置好,其实这段代码都是默认值,如果不需要改变缓存的大小及位置,则不需要写这段代码,默认位置存储在

    (user home directory)/Library/Caches/(application bundle id)
    

    这个路径下,会生成一个数据库文件,如图所示。

    默认存储路径
    这篇文章 对Cache.db 进行了很好的分析。

    四种缓存策略

    NSURLRequestReloadIgnoringLocalCacheData: 忽略缓存,必须从远程地址下载;
    NSURLRequestReturnCacheDataElseLoad:只要本地有缓存就使用本地的缓存(不管过期时间),只有本地没有缓存的时候才使用远程地址下载;
    NSURLRequestReturnCacheDataDontLoad:只从本地缓存获取内容,如果本地没有的话,也不会去远程地址下载(也就是离线模式);
    NSURLRequestUseProtocolCachePolicy:默认缓存策略;

    NSURLSession缓存设置

    第一种直接url 访问

    - (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler
    

    这里不能对该 url 的 request 进行设置,缓存也使用的是默认缓存策略NSURLRequestUseProtocolCachePolicy。

    第二种 request 访问

    - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;
    

    这种方法可以通过生成request,来设置这个URL 特有的缓存策略,例如:

    NSURLRequest * request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];
    

    AFNetworking 缓存设置

    AFNetworking 使用 sessioManager 来进行网络访问,代码如下

    AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    [manager.requestSerializer setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
    [manager GET:@"http://www.jianshu.com/p/88719de97921" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            NSLog(@"请求成功");
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            NSLog(@"请求失败");
        }];
    

    主要可以通过这段代码来设置缓存策略

    [manager.requestSerializer setCachePolicy:(NSURLRequestCachePolicy)];
    

    NSURLSession 和 AFNetworking 缓存的对比

    区别

    虽然 AFNetworking 本质上也是使用 NSURLSession 来进行网络访问,但是测试过发现其返回结果还是有区别的,NSURLSession 的方法默认都是采用 NSURLRequestUseProtocolCachePolicy:默认缓存策略,在无网络的情况下如果有缓存,error 会返回nil,data 则返回上一次缓存的data。
    而AFNetworking 在NSURLRequestUseProtocolCachePolicy 这个默认缓存策略下,无网络且有缓存的情况下 并不会进入 success 回调,而是进入 failure 回调,原因还需要探索一下。

    相同点

    NSURLRequestReturnCacheDataElseLoad(只要本地有缓存就使用本地的缓存(不管过期时间),只有本地没有缓存的时候才使用远程地址下载;)在这种缓存策略下,并且有缓存的情况下,AFN 无论是否断网都会进入 success 回调,NSURLSession 回调中 error 也会为nil。

    缓存过期机制

    最有效率的缓存是只有在服务端数据发生变化时,或者超过了服务器设置的缓存超时时间,才会去再次服务端请求数据。

    首先,要设置成

    NSURLRequestUseProtocolCachePolicy:默认缓存策略
    

    其次就需要服务端的设置,主要是在响应头中设置 Cache-Control

    Cache-Control
    这个头必须由服务器端指定以开启客户端的 HTTP 缓存功能。这个头的值可能包含 max-age(缓存多久),是公共 public,还是私有 private,或者不缓存 no-cache等信息。详情请参阅 Cache-Control section of RFC 2616

    除了 Cache-Control以外,服务器也可能发送一些附加的头用于根据需要有条件地请求:

    Last-Modified 顾名思义,是资源最后修改的时间戳,往往与缓存时间进行对比来判断缓存是否过期

    ETag用于放置文件的唯一标识,比如文件MD5值。

    对于最常用的 NSURLRequestUseProtocolCachePolicy, 我们需要有两个注意的地方,即使当一个请求在本地存在缓存的情况下,如果这个请求需要重新验证,那系统还是会发起一个 HEAD 请求到服务器上去确定内容是否已经被修改过,如果修改的话还是会重新下载;如果缓存内容不需要验证,那系统只需要确定缓存时间是不是已经过期就可以了。

    不使用缓存策略

    如果觉得缓存策略不太满意,可以将缓存策略设置成这个:

    NSURLRequestReloadIgnoringLocalCacheData 忽略本地缓存,只从服务端获取
    

    从服务端获取成功之后,会产生缓存。然后使用NSURLResponse 来取出某个 Request 对应的本地缓存,自己判断什么时候从服务端获取,什么时候读取本地缓存,就当作一个单独的数据库来使用。

    NSCachedURLResponse *response = [cache cachedResponseForRequest:request];
    

    推荐文章

    相关文章

      网友评论

        本文标题:使用NSURLCache做AFN和NSURLSession的缓存

        本文链接:https://www.haomeiwen.com/subject/oghnuxtx.html