使用NSURLCache做AFN和NSURLSession的缓存

图片源于网络

最近使用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];

推荐文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容