关于使用沙盒与缓存进行 UITableView 异步图像下载的建议

Posted

技术标签:

【中文标题】关于使用沙盒与缓存进行 UITableView 异步图像下载的建议【英文标题】:Advice on using sandbox vs. caching for UITableView async image download 【发布时间】:2009-11-23 14:51:32 【问题描述】:

一周前,Apple 刚刚发布了一些关于在 UITableView 中延迟加载图像的示例代码。我检查了它并将其实现到我自己的 UITableView(这是一个用于快速滚动的 drawRect)中,看看是否与我已经在做的不同。

实施后我不确定什么是最好的;新代码或我已经拥有的代码。我的 3GS 速度没有太大提升。

“沙盒”方法:懒加载图片,然后保存到沙盒中的本地tmp文件夹。 每次显示单元格时,它会查找具有该文件名的图像是否已位于沙盒文件夹中。如果是,它会检索图像并显示它,如果不是,它会继续下载,将其保存在本地,然后显示它。这样做的好处是第二次打开应用程序时图像不会是空白的。它们已经被下载并准备好显示了。

缓存方法:这也会延迟加载图像,但是,现在我在 tableview 中显示的数组中的每个对象上都包含一个 UIImage。我现在不是在本地保存图像,而是下载图像并将其放入对象的数组中。现在,它不再每次都检查文件名,而是检查 UIImage 是否!= nil 并使用缓存的图像(如果为 nil,则下载)。

一个小的区别还在于,缓存代码在将图像缓存到单元格中显示的确切大小之前会调整其大小,而沙盒代码示例中使用的图像实际上比它需要显示的要大一些,这意味着它也必须在滚动时动态调整大小。几个月前我读到这可能有点贵,而且我也不确定在使用缓存图像而不是沙箱存储的图像方面是否有很大的不同,因此无论如何都需要更多的 CPU 密集型(比较到您使用上面的缓存代码从缓存中保存的内容)。

我想我的问题是我是否应该打扰缓存代码?同样,新代码不会在新启动时立即加载图像,而旧代码实际上会这样做,因为它已经在沙箱中。由于我没有重用图像,我有很多图像要加载(从沙箱或缓存中),所以我没有注意到速度上有很大的差异。事实上,在我看来,在我的 3GS 上几乎无法分辨。滚动不是如丝般顺滑,我认为这是由于我无法重复使用大量图像(每个单元格的图像不同)。我还想知道,例如,一旦文件夹中有 1000 多张图像,沙盒方法是否会变慢,例如,最终让它查看更多的图像,而不仅仅是 100 张左右。

我希望我说得通。我想对细节进行透彻,如果需要,我很乐意提供更多细节。

谢谢!

【问题讨论】:

对于现在阅读这篇文章的任何人(因为这是一篇旧文章),我强烈建议您查看 AFNetworking 中的内置图像缓存或出色的 UIImageView/UIImage 扩展 SDWebImage,它们都可以处理缓存和异步下载。 【参考方案1】:

如果您的代码已经可以运行,并且没有紧迫的问题,请不要更改它。

如果你的滚动实际上太慢了,那么也许你可以混合使用想法,并尝试获取 UIImage,如果它不存在,从沙箱加载它,如果它是没有,那就下载吧。

【讨论】:

我已经在执行“如果不存在则下载,然后保存,然后从沙箱加载”的方法。它只是对图像进行“沙盒化”并以这种方式检索它或将其放入对象的 uiimage 对象中。【参考方案2】:

判断性能是否存在明显差异的唯一好方法是使用分析工具,例如 Instruments(用于测量两种技术的显示帧速率等)或 Shark(用于确定代码中的热点)。您的具体实现可能存在细微差异,这可能会导致我们给出的任何一般性答案与您在应用程序中看到的实际性能之间存在显着差异。

“沙盒”方法主要关注的不是性能,而是磁盘空间使用情况。用户不会喜欢你用不必要的文件填满他们的 iPhone 或 iPod Touch,尤其是如果所有图像都没有被一致使用或者使用的图像集经常变化。如果不了解您的应用程序的更多信息,就无法猜测这些缓存图像的加载频率。

如果您在自己的设备上进行本地测试,则可能是在 Wifi 网络上。我的建议是在您的部分测试中关闭 Wifi,以查看当您必须通过蜂窝网络获取所有图像时这两种方法的执行情况。我还建议您尝试寻找旧设备(iPhone 3G 或更差的设备),因为 3GS 实际上隐藏了可能会令旧设备用户烦恼的潜在性能问题。

我个人在我的应用程序中多次使用 LazyTableImages 技术(前提是它在 WWDC09 和最近的“发布”之间没有发生太大变化),并且发现它正是我所需要的。但是,在我的情况下,将图像缓存在磁盘上不是一种选择,而且您不应该过于重视我的轶事 - 分析您自己的代码并使用它显示的结果。

编辑:

显而易见的答案是访问内存中的缓存将比访问文件系统更快,但当然最后的决定权留给分析。如果图像已经在内存中,则不需要从闪存中读取它们并由 UIImage 解析。然而,传统的权衡在这里发挥作用 - 内存缓存与磁盘空间。

虽然将图像存储在内存中可能会更快,但您需要非常确定您正确处理应用程序中的内存警告(无论如何您都应该这样做!)。否则长时间使用会导致内存缓存中有很多图像并触发内存警告,如果您的应用程序不是为处理这些问题而构建的,那么您的应用程序最多会因内存资源不足而被操作系统杀死。

【讨论】:

感谢您的洞察力。关于。沙箱,它在 tmp 文件夹中,所以它不会被备份。我还将限制设置为 10MB,如果沙盒大小达到 10MB+,则将其清除。我懒惰地下载图片的方法基本相同,所以我不太关心实际下载图片是否更快。我更感兴趣的是看看两者中哪一个在性能方面更快(缓存与沙盒)。【参考方案3】:

您介绍的这两种方法各有利弊 - 我建议在您的应用中使用这两种方法的元素。

最好将图像保存在内存中并稍后保存(可能在您的应用退出时)。如果你有很多图像,使用 Core Data 保存它们可能比保存常规文件更快。

最好避免即时调整大小,即在 tableView:cellForRowAtIndexPath: 或 tableView:willDisplayCell:forRowAtIndexPath: 方法或与绘制单元格内容视图有关的任何方法中。如果可以,请让图像提供者(内容管理?)以表格视图显示的大小提供图像。

【讨论】:

以上是关于关于使用沙盒与缓存进行 UITableView 异步图像下载的建议的主要内容,如果未能解决你的问题,请参考以下文章

iPhone APNS 沙盒与尚未批准应用的生产对比

贝宝沙盒与真实账户

Qiankun框架对于微前端的解耦和沙盒与实战探索心得

关于白盒与黑盒

如何 判断 ios 应用 沙盒

如何测试 SKPaymentTransactionStateDeferred?