与CGContextDrawImage相比,为什么UIImageView的内存密集程度如此之高

时间:2011-02-10 09:45:08

标签: ios pdf uiimageview quartz-graphics

开发iPad PDF-Reader我们决定准备渲染密集页面的高分辨率图像(其中包含许多路径),并使用这些图像而不是pdf页面来避免性能问题。我们认为 3*768 by 3*1024 是可读性和渲染性能之间的良好折衷,导致 ~1.5 MB jpegs

然而,我们测试了两个用于显示图像页面的实现。一个使用CATiledLayer子类,它还负责处理“普通”PDF页面(使用CGContextDrawImage绘图),另一个使用UIImageView。后者的优点是显示和缩放非常快,但内存使用非常糟糕 - 内存大约需要<30> (这与图像的位图大小一致)。另一种方法(CATiledLayer)需要更多时间来首次显示页面,并且在缩放后需要另外两秒钟来重新渲染(类似于pdf页面,但速度要快得多)但是不会占用更多内存而不是需要显示小得多的图像或PDF页面。

有没有人知道幕后发生了什么,以及是否可以通过使用Quartz Framework将CGContextDrawImage的低内存使用率与UIImageView的高性能结合起来。

1 个答案:

答案 0 :(得分:4)

不确定这个问题是否仍然相关,但如果是这样,也许这会有所帮助:

我也在我的tiled image view中进行了有效展示大型观看的战斗。这个问题有许多潜在的部分:

  • 正常UIView,包括UIImageView,似乎总是完全由内存支持其图像。即使您实现了drawRect:方法,它似乎也总是传递视图的整个边界,而不仅仅是滚动视图中可见的区域。正如您所发现的,这会快速占用 lot 内存,因为每个像素占用4个字节。
  • CATiledLayer 仅请求可见图块的内容。它还会丢弃不再可见的磁贴 - 这是节省内存的地方。但是,它会在后台线程上进行通知和绘图,同时从白色动画到内容。它似乎通过私有API来做到这一点,我还没有找到一种方法来重新实现CATiledLayer的功能作为我自己的CALayer的子类,因为似乎没有通知机制我们可以用作凡人。
  • 如果您在滚动视图中有多个视图,则会在他们被分页时正确地收到drawRect:个消息。但是,UIKit似乎很难在视图下方查看过多的子视图。

对你而言,我可以看到几个可能的选择:

  • 有可能挽救基于CATiledLayer的实施。 fadeDuration默认为0.25秒,如果加载时间很短,则可能太长。你可以将它放到像1.0/60.0这样的东西,即一帧。从您的描述中不清楚的一件事是您的图像是覆盖整个页面大小还是仅覆盖每个256x256像素的图块。对每个图块一遍又一遍地解码整个JPEG将比解码单个图块文件慢得多。
  • 如果从CATiledLayer线程执行所有操作的延迟太高,您可以手动创建一堆瓷砖UIImageView子视图到空白UIView,这是主要的子视图滚动视图。这些子视图中的每一个都被分配了自己的图块图像。如果你很幸运,UIKit将足够聪明地删除这些视图的内容并按需重新加载相应的JPEG。
  • 如果UIImageViews不够智能,或者您有太多的视图无法应对UIKit,您可以构建自己的视图,在drawRect:中加载其JPEG。如果它仍然太生涩,请尝试使用您自己的CALayers,它将是您单个视图的空白图层的子图层,并再次根据需要加载图像。这是我最终用于平铺图像视图的内容。

这应该涵盖滚动,但如果允许用户缩小(缩小),它仍然可能非常慢。在这种情况下,我建议您存储适当的低分辨率版本,并在那些最外面的缩放级别加载/显示那些。