让 UIView drawRect 发生在后台线程中

Posted

技术标签:

【中文标题】让 UIView drawRect 发生在后台线程中【英文标题】:Having UIView drawRect occur in a background thread 【发布时间】:2014-01-15 13:54:06 【问题描述】:

我希望有一个UIView 子类,它实现类似于setNeedsDisplay 的方法,除了重绘(即,通常通过drawRect: 调用)将很快发生在后台线程中,而不是在当前更新周期结束时。

它可能被称为setNeedsAsynchronousDisplay。或者现有的setNeedsDisplay 可能会被劫持并且不会在循环结束时导致重绘,或者其他任何情况,只要它让重绘不会发生在主线程阻塞屏幕上,更新交互直到完成。

在重绘发生之前,视图可以继续使用其当前绘制的表示。

这些方面的事情是否合理可行?

谢谢!

【问题讨论】:

【参考方案1】:

是的,这是可能的。您可能需要在背景中将内容视图生成为图像并将图像推送到 nsdictionary 或数组中。

因此,当您的背景生成图像时,您可以通过渲染图像在 drawrect 函数中显示图像,前提是图像已经生成。

展示如何操作的 WWDC 视频:WWDC 2012 session 211 - Building Concurrent User Interfaces on ios。以下是视频说明:

为了获得出色的用户体验,在呈现复杂的 UI 元素和处理数据时保持应用程序的响应性至关重要。了解如何在 UIKit 层使用并发来执行绘图和其他常见操作,而不会阻塞用户交互。

【讨论】:

看完视频后非常兴奋,甚至尝试自己搭建一个。对于没有很多交互(如按钮或突出显示状态)的单元格视图来说,它更实用。如果你自己建造了一个,请告诉我。 感谢@Ethan,从描述中听起来确实很有帮助。我今天会看看那个。 哦,我实现了这个,它工作得非常好。谢谢:-) Apple 团队的工作真的很棒,感谢视频@Ethan Fang 很遗憾,该视频已无法在任何地方观看。在 Apple 将其撤下之前,是否有人有机会将其保存副本或写下笔记?【参考方案2】:

没有。 视图 绘图必须发生在前景中。 Apple 在他们的文档中非常清楚地说明了这一点。

编辑:你是对的,只要不在 UIView 对象的绘图方法中,你就可以在后台绘制核心图形。您必须在后台进行绘图,然后在绘图完成后向主线程发送消息以更新您的视图对象。

我建议不要尝试覆盖 setNeedsDisplay。相反,添加新的 setNeedsAsynchronousDisplay 方法。在该方法中,使用 GCD 调用将渲染代码排队到异步队列。渲染完成后,让渲染代码在主线程上向自身发送 setNeedsDisplay 消息。

然后在您的子类的 drawRect 方法中,检查预渲染的图像并将它们绘制到视图的上下文中,而不是普通代码。

这样做的一个缺点是,仅通过实现 drawRect,您可能会减慢渲染速度,因为系统调用它而不是执行其他更有效的事情来渲染您的视图内容。

【讨论】:

谢谢@Duncan C,但我不相信iOS 4 的Core Graphics 操作(但不是它们的UI 包装器)就是这种情况。请参阅此technical note at Apple。我怀疑 UIView 更新确实需要在主线程中,但这并不意味着绘图不能在另一个表面的背景中发生然后被交换。我在寻求想法/建议/最佳实践/完整的解决方案。 我没用过“drawRect inContext”,也许值得一试。

以上是关于让 UIView drawRect 发生在后台线程中的主要内容,如果未能解决你的问题,请参考以下文章

UIView 在后台调用 drawRect

UIView的layoutSubviews和drawRect方法何时调用

UIView的layoutSubviews和drawRect方法何时调用

UIView的layoutSubviews和drawRect方法何时调用

UIView的layoutSubviews和drawRect方法何时调用

如何使用 drawRect 覆盖在 UIView 子类的某些区域中获得透明度