11

我刚刚花了很长时间在 NSURLCache 上大喊大叫,所以我提供一些建议,希望其他人可以避免我的不幸。

这一切都以合理的方式开始。我的新应用项目只针对 iOS 5 及更高版本,所以我认为我可以利用新的 NSURLCache 实现来满足我所有的 Web 缓存需求。我需要一个 NSURLCache 的自定义子类来处理一些特殊任务,但这一切似乎都得到了 API 的有用支持。快速阅读文档,我开始参加比赛:

[NSURLCache setSharedURLCache:[[MyCustomCache alloc] initWithMemoryCapacity:8 * 1024 * 1024 //8mb 
                                                                    diskCapacity:32 * 1024 * 1024 // 32mb 
                                                                        diskPath:@"webcache.db"]];

我认为 8mb 的缓存可以开始,我会用更大的磁盘缓存来支持它,这样我们就可以在本地提供更多更大的图像。我连接了其余的网络代码以使用 NSURLConnection (实际上,我使用了 MKNetworkKit,但结果证明这无关紧要),并期待我的缓存中有很棒的东西。果然,所有应该被缓存的请求都尽职尽责地保存到缓存中,并且当响应从缓存中得到服务时,它们会尽职尽责地快速返回。这是《彭赞斯海盗》的常规制作,在我的网络堆栈中飞来飞去的职责如此之多。

除了没有加起来。可以从缓存中提供服务的请求仍然通过网络发送出去。除非他们不是。缓存是否实际用于服务请求似乎完全随机且断断续续。我沮丧地扯下头发,从字面上挖掘一切,试图弄清楚发生了什么。我构建测试应用程序,在各处设置断点,撕开数据包跟踪,阅读互联网上提到 NSURLCache 的每一个字,试验缓存控制标头,注释掉代码,绕过我的子类,甚至煞费苦心地追踪NSURLCache 及其 CFNetworking 朋友的程序集,试图了解其背后的神秘逻辑。我极大地提高了我对 ARM 和 Objective-C 调用约定的了解,并学习了一些关于低级调试的知识,但在真正弄清楚发生了什么方面却一无所获。整件事感觉更像是 Iolanthe 的噩梦之歌比起海贼王的良性独裁统治,我几乎快要把它全部扔掉了。

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

4

2 回答 2

9

最终,我尝试对我一直在摆弄的所有位进行不同的排列。我将内存和磁盘缓存大小都设置为 8mb。

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

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

因此,伴随着笑声和欢快的舞蹈,我检查了我的两行修复程序并匆忙前往酒吧,最终与 SO(以及一份 Apple 错误报告)分享了这些知识,希望其他人不必经历这个又痛了。

这个悲惨故事的寓意是:如果您尝试在磁盘容量大于内存容量的 iOS5 上使用 NSURLCache,就会发生奇怪和邪恶的事情。不要这样做。并避免与魔法仙女为敌。

于 2012-07-16T03:57:09.620 回答
2

FWIW 这是我的最终解决方案:

https://gist.github.com/3245415

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

于 2012-08-07T06:04:15.313 回答