如何提高包含大量小图像的UCollectionView的性能? [英] How to improve performance of UCollectionView containing lots of small images?

查看:116
本文介绍了如何提高包含大量小图像的UCollectionView的性能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的iOS应用中,我有 UICollectionView ,显示大约1200个小(35x35点)图像。图像存储在应用程序包中。

In my iOS app I have UICollectionView that displays around 1200 small (35x35 points) images. The images are stored in application bundle.

我正确地重用 UICollectionViewCell 但仍然存在性能问题,具体取决于关于如何处理图像加载:

I am correctly reusing UICollectionViewCells but still have performance problems that vary depending on how I address image loading:


  • 我的应用程序是应用程序扩展,内存有限(在这种情况下为40 MB)。将所有1200个图像放入Assets目录并使用 UIImage(名称:imageName)加载它们导致内存崩溃 - 系统缓存的图像填满了内存。在某些时候,应用程序需要分配更大的内存部分,但由于缓存的图像,这些内存不可用。操作系统刚刚杀死了应用程序,而不是触发内存警告和清理缓存。

  • My app is application extension and those have limited memory (40 MB in this case). Putting all 1200 images to Assets catalog and loading them using UIImage(named: "imageName") resulted in memory crashes - system cached images which filled up the memory. At some point the app needs to allocate bigger portions of memory but these were not available because of cached images. Instead of triggering memory warning and cleaning the cache, operating system just killed the app.

我改变了方法以避免图像缓存。我将图像作为png文件放入我的项目(而不是asssets目录),我使用 NSBundle.mainBundle()加载它们.pathForResource(imageName,ofType:png)现在。该应用程序不再因内存错误而崩溃,但单个图像的加载需要更长时间,即使在最新的iPhone上,快速滚动也会滞后。

I changed the approach to avoid images caching. I put images to my project (not to asssets catalog) as png files and I am loading them using NSBundle.mainBundle().pathForResource("imageName", ofType: "png") now. The app no longer crashes due to memory error but loading of single image takes much longer and fast scrolling is lagging even on the newest iPhones.

我对图像有完全的控制权,可以将它们转换为.jpeg或优化它们(我已经尝试过了) ImageOptim 和其他一些选项没有成功。)

I have full controll over the images and can transform them for example to .jpeg or optimize them (I already tried ImageOptim and some other options without success).

怎么能我立刻解决了这两个性能问题?

How can I resolve both these performance problems at once?

编辑1:

我也尝试在后台线程中加载图像。这是我的子类 UICollectionViewCell 中的代码:

I also tried loading images in background thread. This is code from my subclass of 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
                }
            })
        }
    })
}

当以编程方式滚动到某个位置时(例如当 UICollectionView 滚动到顶部时)这会使滚动变得平滑而不会消耗额外的内存来缓存导致另一个问题:在滚动动画期间,图像不会更新(滚动速度太快它们加载)并且在滚动完成后,它会显示错误的图像显示为秒的一小部分 - 并且一个接一个地用正确的图像替换。这在视觉上非常令人不安。

This makes scrolling smooth without consuming additional memory for caching but when scrolling to some location programatically (for example when UICollectionView scrolls to top) it causes another problem: During scrolling animation the images do not update (scroll is too fast for them to load) and after scrolling is finished it takes wrong images are displayed for fraction of second - and one after another replaced with correct ones. This is very disturbing visually.

编辑2:

我无法将小图像分组到更大的合成图像中,并按照此答案的建议显示这些图像。

I cannot group small images into bigger composed images and display those as suggested by this answer.

理由:


  • 考虑不同的屏幕尺寸和方向。必须为每个人预先组合图像,这将使应用程序下载量巨大。

  • 小图像可以按不同顺序显示,其中一些可能在某些情况下隐藏。我完全不能为每种可能的组合和订单提供预先组合的图像。

推荐答案

我可以提出替代方案可能可以解决您的问题的方式:

考虑将图像块渲染为单个合成图像。这样大的图像应该覆盖app窗口的大小。对于用户来说,它看起来像是小图像的集合,但从技术上讲它将是大图像的表格。

I can propose alternative way that probably can solve your problem:
Consider to render blocks of images to single composed images. Such large image should cover size of app window. For user it will be looked like collection of small images, but technically it will be table of large images.

您当前的布局:

 |      |      |      |
 | 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
 |                    |

理想情况下,如果你预先渲染这样的合成图像并在构建时将它们投射到项目中,但你可以也在运行时渲染它们。当然,第一个变体的工作速度要快得多。但无论如何,单个大图像会花费更少的内存,然后分离该图像。

Ideally if you pre-render such composed images and put them to project at build time, but you can also render them in runtime. For sure first variant will work much more faster. But in any case single large image costs less memory then separate pieces of that image.

如果你有可能预先渲染它们,那么使用JPEG格式。在这种情况下,您的第一个解决方案(在主线程上加载 [UIImage imageNamed:] 的图像)可能会正常工作,因为使用的内存更少,布局更简单。

If you have possibility to pre-render them then use JPEG format. In this case probably your first solution (load images with [UIImage imageNamed:] on main thread) will work good because less memory used, layout is much more simpler.

如果你必须在运行时渲染它们,那么你将需要使用当前的解决方案(在后台工作),当你快速动画时你仍会看到图像错位,但在这种情况下,它将是单个错位(一个图像覆盖窗框),所以它应该看起来更好。

If you have to render them in runtime then you will need use your current solution (do work in background), and you will still see that image misplacements when quick animation happens, but in this case it will be single misplacement (one image covers window frame), so it should look better.

如果您需要知道用户点击的图片(原始小图片35x35),您可以使用 UITapGestureRecognizer 附加到细胞。识别手势后,您可以使用 locationInView:方法计算小图像的正确索引。

If you need to know what image (original small image 35x35) user clicked, you can use UITapGestureRecognizerattached to cell. When gesture is recognized you can use locationInView: method to calculate correct index of small image.

我不能说它100%解决了你的问题,但尝试尝试是有意义的。

I can't say that it 100% resolves your issue, but it makes sense to try.

这篇关于如何提高包含大量小图像的UCollectionView的性能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆