Caching NSURLCache在iOS5上提供不一致的结果,看起来是随机的

Caching NSURLCache在iOS5上提供不一致的结果,看起来是随机的,caching,ios5,nsurlconnection,nsurlcache,Caching,Ios5,Nsurlconnection,Nsurlcache,我只是花了太长时间在NSURLCache大喊大叫,所以我提出这一点建议,希望其他人能避免我的不幸 这一切一开始就很合理。我的新应用项目只针对iOS5及以上版本,因此我认为我可以利用新的NSURLCache实现满足我所有的web缓存需求。我需要一个自定义的NSURLCache子类来处理一些特殊任务,但这些似乎都得到了API的支持。快速阅读文档,然后我就开始比赛了: [NSURLCache setSharedURLCache:[[MyCustomCache alloc] initWithMemory

我只是花了太长时间在NSURLCache大喊大叫,所以我提出这一点建议,希望其他人能避免我的不幸

这一切一开始就很合理。我的新应用项目只针对iOS5及以上版本,因此我认为我可以利用新的NSURLCache实现满足我所有的web缓存需求。我需要一个自定义的NSURLCache子类来处理一些特殊任务,但这些似乎都得到了API的支持。快速阅读文档,然后我就开始比赛了:

[NSURLCache setSharedURLCache:[[MyCustomCache alloc] initWithMemoryCapacity:8 * 1024 * 1024 //8mb 
                                                                    diskCapacity:32 * 1024 * 1024 // 32mb 
                                                                        diskPath:@"webcache.db"]];
我认为8mb的缓存可以启动,我将使用更大的磁盘缓存来支持它,这样我们就可以在本地为更多更大的图像提供服务。我将网络代码的其余部分连接起来使用NSURLConnection(实际上,我使用了,但结果证明这是不相关的),并期望从缓存中得到很多东西。果不其然,所有应该缓存的请求都会尽职尽责地保存到缓存中,当响应从缓存中得到服务时,它们会尽职尽责地快速返回。这是《彭赞斯海盗》的常规制作,在我的网络堆栈中有很多任务

只是有些事情不对劲。可以从缓存服务的请求仍然通过网络发出。除非他们不是缓存是否真的用于服务请求,这看起来完全是随机的、断断续续的。我沮丧地扯下头发,仔细研究所有东西,试图弄清楚到底发生了什么。我构建测试应用程序,到处设置断点,撕开数据包跟踪,阅读互联网上提到NSURLCache的每个单词,尝试缓存控制头,注释掉代码,绕过我的子类,甚至可以通过对NSURLCache和它的朋友们的程序集进行艰苦的追踪,试图了解其背后隐藏着什么神秘的逻辑。我极大地提高了对ARM和Objective-C调用约定的了解,并学习了一些关于低级调试的知识,但在实际了解发生了什么方面却一事无成。整个事情感觉更像是Iolanthe的,而不是海盗王的温和独裁,我几乎就要把它扔掉了


TL/DR版本:NSURLCache似乎正在工作,但即使缓存结果可用,它也不会随机返回这些结果。

最终,我尝试了一种不同的排列方式来处理我一直在处理的所有位。我将内存和磁盘缓存大小都设置为8mb

瞧,所有的怪异都消失了!应该缓存的所有内容都将被保存。所有应该来自缓存的东西都可以在没有网络请求的情况下得到服务

iOS5中的NSURLCache实现似乎还没有完成。它确实使用磁盘和内存缓存(不像iOS4和更早版本,后者只实现内存缓存),但当请求未命中时,它实际上不会通过内存缓存传递到磁盘缓存。因此,不管给定的响应是否恰好在正确的时刻出现在内存中,基本上都是盲目的运气(好吧,盲目的运气受所有其他网络和缓存使用的影响)。这可能有助于减少设备上的闪存文件IO,但如果您期望类具有理性的行为,这将是非常令人讨厌的

因此,随着欢笑的歌声和欢快的舞蹈,我检查了我的两行修复程序,并赶紧去酒吧,最终与so(以及一份苹果病毒报告)分享了这些知识,希望没有其他人再经历这种痛苦


这个不幸故事的寓意是:如果你试图在iOS5上使用磁盘容量大于内存容量的NSURLCache,那么奇怪和邪恶的事情就会发生。不要这样做。避免与魔法精灵为敌

FWIW以下是我的最终解决方案:


它需要使用FMDB,但效果非常好。

它让我感觉好多了,但即使后来我还是有些奇怪。NSURLCache似乎存在一些严重的同步问题(?)。我已经提交了一个雷达文件,在此期间,我将所有的图像缓存移到了一个相当混乱的SDWebImage()分支,它至少表现出决定性的行为。这是一个不错的方法。我曾想过尝试类似的方法,但最终还是担心自己会弄脏SQLite DB,因为它显然表现得如此不可预测。我会担心您的修复程序的同步问题,尽管在实践中可能一切正常。正如我前面所说,我一直在使用SDWebImage的NSCache-backed fork(请参阅pull请求)来处理图像缓存,并且对结果非常满意。您是在尝试将缓存用于NSURLConnection还是UIWebView,或者两者都使用?几个月前,我在WWDC与Safari开发人员讨论了UIWebView缓存。他说有一种双层缓存。从我自己的调试测试中,我发现在检查操作系统级Safari缓存之前,会先检查
+[NSURLCache sharedullcache]
。但是,响应不会缓存在应用程序的共享缓存中,谁知道操作系统级缓存的行为。有趣。我只关注了NSURLConnection方面,因为我们的应用程序没有充分利用UIWebView。我确实记得读到过,应用程序没有使用操作系统级别的Safari缓存,但我相信事实并非如此,尤其是对于UIWebView。