在我的 iOS 应用程序中我有UICollectionView
显示大约 1200 个小(35x35 点)图像。图像存储在应用程序包中。
我正确地重用了UICollectionViewCell
但仍然存在性能问题,具体取决于我处理图像加载的方式:
我的应用程序是应用程序扩展,它们的内存有限(在本例中为 40 MB)。将所有 1200 个图像放入 Assets 目录并使用加载它们UIImage(named: "imageName")
导致内存崩溃 - 系统缓存的图像填满了内存。在某些时候,应用程序需要分配更大的内存部分,但由于缓存的图像,这些内存不可用。操作系统没有触发内存警告并清理缓存,而是杀死了应用程序。
我改变了方法以避免图像缓存。我将图像作为 png 文件放入我的项目(而不是资产目录)中,然后使用加载它们NSBundle.mainBundle().pathForResource("imageName", ofType: "png")
现在。该应用程序不再因内存错误而崩溃,但加载单个图像需要更长的时间,即使在最新的 iPhone 上,快速滚动也会出现滞后。
我可以完全控制图像,并且可以将它们转换为 .jpeg 或优化它们(我已经尝试过图像优化 https://imageoptim.com以及其他一些没有成功的选项)。
如何同时解决这两个性能问题?
EDIT 1:
我还尝试在后台线程中加载图像。这是我的子类的代码UICollectionViewCell
:
private func loadImageNamed(name: String) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { [weak self] () in
let image = bundle.pathForResource(name, ofType: "png")?.CGImage
if name == self?.displayedImageName {
dispatch_async(dispatch_get_main_queue(), {
if name == self?.displayedImageName {
self?.contentView.layer.contents = image
}
})
}
})
}
这使得滚动平滑,而不消耗额外的内存进行缓存but当以编程方式滚动到某个位置时(例如当UICollectionView
滚动到顶部)这会导致另一个问题:在滚动动画期间,图像不会更新(滚动速度太快,无法加载),并且滚动完成后,会在几分之一秒内显示错误的图像 - 然后一个又一个地替换为正确的图像。这在视觉上非常令人不安。
EDIT 2:
我无法将小图像分组为更大的合成图像并按照建议显示这些图像这个答案 https://stackoverflow.com/a/31869978/311865.
理由:
- 考虑不同的屏幕尺寸和方向。每个应用程序都必须有预先合成的图像,这将使应用程序下载量很大。
- 小图像可以以不同的顺序显示,其中一些在某些情况下可能会隐藏。我肯定无法为每种可能的组合和顺序预先合成图像。
我可以提出可能可以解决您的问题的替代方法:
考虑将图像块渲染为单个合成图像。如此大的图像应该覆盖应用程序窗口的大小。对于用户来说,它看起来像是小图像的集合,但从技术上讲,它将是大图像的表格。
您当前的布局:
| | | |
| cell | cell | cell | -> cells outside of screen
| | | |
************************
*| | | |*
*| cell | cell | cell |* -> cells displayed on screen
*| | | |*
*----------------------*
*| | | |*
*| cell | cell | cell |* -> cells displayed on screen
*| | | |*
*----------------------*
*| | | |*
*| cell | cell | cell |* -> cells displayed on screen
*| | | |*
************************
| | | |
| cell | cell | cell | -> cells outside of screen
| | | |
建议布局:
| |
| cell with |
| composed image | -> cell outside of screen
| |
************************
*| |*
*| |*
*| |*
*| |*
*| cell with |*
*| composed image |* -> cell displayed on screen
*| |*
*| |*
*| |*
*| |*
*| |*
************************
| |
| cell with |
| composed image | -> cell outside of screen
| |
理想情况下,如果您预先渲染此类合成图像并在构建时将它们放入项目中,但您也可以在运行时渲染它们。可以肯定的是,第一个变体的工作速度会更快。但无论如何,单个大图像比单独的图像片段花费更少的内存。
如果您可以预渲染它们,请使用 JPEG 格式。在这种情况下,可能是您的第一个解决方案(使用[UIImage imageNamed:]
在主线程上)会很好地工作,因为使用的内存更少,布局更简单。
如果您必须在运行时渲染它们,那么您将需要使用当前的解决方案(在后台工作),并且当快速动画发生时您仍然会看到图像错位,但在这种情况下,它将是单个错位(一个图像覆盖窗口框架),所以它应该看起来更好。
如果您需要知道用户点击了什么图像(原始小图像35x35),您可以使用UITapGestureRecognizer
附着在细胞上。当识别手势时,您可以使用locationInView:
小图像正确指数计算方法
我不能说它 100% 解决你的问题,但尝试是有意义的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)