【问题标题】:CoreGraphics (drawRect) for drawing label's and UIImageView in UITableViewCellCoreGraphics (drawRect) 用于在 UITableViewCell 中绘制标签和 UIImageView
【发布时间】:2012-12-07 18:14:19
【问题描述】:

我有一个UITableViewCell,其中有5 个UILabel、一个UIButton 和一个UIImageView,它们将单元格作为背景填充。性能似乎有点慢,所以我正在考虑使用CoreGraphics 来改进它。使用CoreGraphics 而不是UILabel 作为subViews 是否真的会让事情变得更快?如果是,为什么?

我有以下代码在单元格上绘制阴影:

[self.layer setBorderColor:[UIColor blackColor].CGColor];
[self.layer setShadowColor:[UIColor blackColor].CGColor];
[self.layer setShadowRadius:10.0];
[self.layer setCornerRadius:5.0];
[self.layer setShadowPath:[[UIBezierPath bezierPathWithRect:self.frame] CGPath]];

【问题讨论】:

    标签: ios iphone objective-c uitableview core-graphics


    【解决方案1】:

    一般来说,(正如 Gavin 指出的那样)我会说您必须首先确认子视图确实会导致滚动抖动。

    在测试 UITableViewCell 滚动性能时,我经常使用 Instruments 中的 Time Profiler。在左侧面板中切换到 Objective-C Only,查看主线程上花费最多的时间。如果您看到大量时间花在重新排列(布局)或绘制子视图上,您​​可能需要使用 CoreGraphics。如果时间花在分配/解除分配上,那么您可能需要检查您的子视图是如何被重用的。如果它们没有被重用,那么这当然会导致性能问题。

    那么当然,你应该看看合成。如果您的子视图不是不透明的(通过 CoreAnimation 工具识别),那么性能可能会受到严重影响。

    另外值得注意的是——要意识到绘制阴影的成本很高,并且根据您的实现,它们可能会在每一帧上重新绘制!您最好的选择是确保所有 CALayer 阴影都完全光栅化,并定义了路径,因此不必从像素蒙版进行实时计算。

    如果您最终确定每个子视图的布局和重绘会导致速度变慢,那么我有几点/解释:

    1. 您对表格视图单元格的绘图例程的实现可能比 Apple 为其视图编写的高度优化的绘图要慢。所以你不会赢得任何重新实现 UIImageView 本身的绘图的战斗。使用 CoreGraphics 绘图时,性能提升来自两个方面:a.) 预渲染以前不透明的视图,并减少视图绘制周期的布局阶段所花费的时间 - 这减少了 GPU/CPU 上的工作量滚动。 b.) 减少单个视图绘图的 CG 上下文切换时间。现在每个元素同时绘制到相同的图形上下文中,从而降低了切换成本。

    2. 在主线程上使用 CoreGraphics 在 drawRect 中绘图使用 CPU 进行绘图,并且根据您的单元格的复杂程度,这可能会导致其自身的抖动。相反,考虑在后台线程中绘制到单独的 CGContext,然后调度工作人员将绘图的内容作为 CGImageRef 插入到 CALayer 中,或者作为 UIImage 插入到 UIImageView 中。 GitHub上有一个幼稚的实现:https://github.com/mindsnacks/MSCachedAsyncViewDrawing

    3. 如果您决定使用后台 CoreGraphics 绘图,请注意目前(2012 年 12 月),我相信在后台线程上绘图时 NSString 绘图类别中存在一个错误,导致回退到 webkit这绝对不是线程安全的。这会导致崩溃,所以目前,请确保异步绘图在串行 GCD/NSOperation 队列中完成。

    【讨论】:

    • 超级棒的小贴士!正是我需要的。你能告诉我如何使 CALayer shadwos 完全光栅化吗?我在原帖上加了影子代码给大家看看
    • 我强烈 UILabel 只是使用 UIKit 的 NSString-drawing 方法; Apple 的代码很少像他们希望你相信的那样“高度优化”。 UIImageView 不同;它覆盖了-displayLayer:,并且近似于self.layer.contents = self.image.CGImage;,它只是在GPU上合成它(尽管图像仍然必须在CPU上解压缩)。
    • @tc - 我想你错过了我的意思。我试图澄清这种情况下的性能增强不会来自实际的 CG 绘图代码本身。哪个是实际的问题:“使用 CoreGraphics 而不是 UILabel 作为子视图真的会让事情变得更快吗?如果是,为什么?”我还想说 Apple 对 UIImageView 和 UILabel 的实现可能不多(或任何)比使用我们自己实现的这些方法要快...但我怀疑它们会慢得多,而且它们可能不会经常中断。
    • @adit - tc 在他的回答中给出了图层光栅化的代码。
    • @OCRickard 当我仅在时间分析器中切换到 Objective-C 时,它给了我一个空表
    【解决方案2】:

    在模拟器上,调试颜色混合层。红色是坏的,绿色是好的。

    更准确地说,红色意味着 GPU 需要进行 Alpha 混合。主要成本是两次绘制像素并可能重新获取额外纹理所需的内存带宽。完全透明的像素真的很糟糕。

    三个修复(所有这些都减少了红色的数量),在深入研究 Core Graphics 之前您应该考虑这些:

    • 尽可能使视图不透明。背景设置为 [UIColor clearColor] 的标签通常可以设置为纯色。
    • 使具有透明度的视图尽可能小。对于标签,这涉及使用-sizeToFit/-sizeThatFits: 并适当调整布局。
    • 从不透明图像中移除 Alpha 通道(例如,如果您的单元格背景是图像) - 一些图像编辑器不这样做,这意味着 GPU 需要执行 Alpha 测试并且可能需要渲染图像后面的任何内容.

    此外,打开和Color Offscreen-Rendered(可能在关闭Color Blended Layers 之后,这样更容易看到)。屏幕外渲染的东西显示为黄色,通常表示您已应用图层蒙版。这些可能对性能非常不利;不知道CoreAnimation是否缓存了被屏蔽的结果。

    最后,您可以通过设置cell.layer.shouldRasterize = YES 使CoreAnimation 栅格化单元格(在视网膜设备上您可能还需要cell.layer.rasterizationScale = [[UIScreen mainScreen].scale;我忘了这是否是自动完成的)。主要的好处是它很简单,而且比自己在 Core Graphics 中渲染图像视图更高效。 (由于文本需要在 CPU 上呈现,因此减少了标签的好处。)

    还要注意视图动画会受到影响。我忘记了 CALayer.shouldRasterize 做了什么设置(它可能会在动画的每一帧重新光栅化它,当它只被绘制到屏幕一次时有点浪费),但使用 Core Graphics 将(默认情况下)拉伸渲染动画期间的内容。请参阅 CALayer.contentsGravity。

    【讨论】:

    • 当你说 make view opaque 是否意味着将 opaque 设置为 YES?
    • 如果我不能使标签具有背景色怎么办。即:不透明,它需要清楚,因为我后面有一个 UIImageView 需要显示,所以将它设置为不透明会很奇怪@tc
    • 对于标签,将背景颜色设置为不透明颜色也会将不透明设置为 YES。
    • 如果您不能使标签不透明,则需要在某处进行 alpha 混合。我的意思不是你应该摆脱所有的 alpha 混合,而是你应该在决定光栅化整个单元格或使用 Core Graphics 绘制所有内容之前将它删除到容易做到的地方。如果您确实栅格化了单元格,请记住检查旋转性能(除非您确定您的应用永远不需要支持旋转)和动画,例如切换到/退出编辑模式。
    • 如何移除 UILabel 上的 alpha 混合?
    【解决方案3】:

    您有什么证据表明您的观点导致了性能问题?这是一个可以把你吸进去的深黑洞,所以请确保你知道问题出在你认为的位置。

    您是否正在预加载所有数据?你有没有预下载图片?你所描述的不应该导致 UITableViewCell 变慢。 Apple developers are much smarter than you and I 所以请确保您有数据来支持您的决定!

    我还在模拟器中看到了一个滞后的 UITableViewCell,在真实硬件上没有明显差异。

    确实,使用 CoreGraphics 可以加快您的绘图性能,但如果您做错了,它也会减慢它的速度!查看Apple Tutorial on Advanced Table View Cells 了解如何执行该技术。

    【讨论】:

    • 我想我的后续问题是何时将其绘制为单个视图而不是子视图。这也在设备上进行了测试。
    • 如果您可以证明您的子视图正在减慢 UITableView 的速度,那么就开始深入研究 CoreGraphics。
    • 如何确定我的子视图是否真的减慢了 UITableView?图片也已预先下载
    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-16
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多