CATiledLayer 显示以前的图块
Posted
技术标签:
【中文标题】CATiledLayer 显示以前的图块【英文标题】:CATiledLayer shows previous tiles 【发布时间】:2017-02-14 22:21:35 【问题描述】:当使由 CATiledLayer 支持的视图无效时,前一个图块仍然“卡住”并且未正确无效。
这似乎发生在视图无效时(在主线程上),而与此同时,瓷砖渲染线程仍在处理先前版本的瓷砖。不是缓存新版本的磁贴,而是缓存以前的版本。
CATiledLayer 支持的视图是 UIScrollView 的子视图,并且是可缩放的。瓦片的渲染可能会很昂贵,并且可以使用渲染线程 10 毫秒。
示例
演示此问题的示例代码:https://github.com/Q42/CATiledLayerBug
-
在 CATiledLayer 中,开始渲染所有红色图块(这大约需要 3 秒才能完成)
每个渲染步骤大约需要 10 毫秒
在渲染期间(800ms 后),使完整视图无效:
tiledView.setNeedsDisplay()
开始渲染所有灰色图块(这同样需要大约 3 秒)
两个图块(随机?)保持红色,而不是变成灰色。
在此处查看update
函数:https://github.com/Q42/CATiledLayerBug/blob/master/TiledLayerTest/ViewController.swift#L45
解决方法?
这似乎是CATiledLayer
的实现中的一个错误。由于我无法解决这个问题,有人知道解决此问题的好方法吗?
我已经为此提交了一个雷达:http://www.openradar.me/28648050
【问题讨论】:
【参考方案1】:根据我添加到示例项目中的一些进一步的日志记录,我认为问题是这样的:
CATiledLayer
有两个渲染线程来绘制每个图块。如果在draw(_: CGRect)
调用的执行过程中调用了setNeedsDisplay
,则draw
调用的当前执行完成并缓存结果。缓存的值基于之前的“数据源”(本例中只是磁贴颜色),而不是更新后的数据源。
Apple 支持工程师向我提供了解决方法:
向 TiledView 添加一个updateID
字段
添加draw(_: CGRect)
调用的开头保存当前updateID
当“数据源”发生变化时,更改updateID
添加draw(_: CGRect)
调用的结尾,将保存的updateID
与当前的比较。
如果 ID 不同,请安排新的 setNeedsDisplay
通话。
摘录:
override func draw(_ rect: CGRect)
let originalID = updateID
// all actual (slow) drawing code here...
if originalID != updateID
// dispatch a redraw request, but wait a little while first
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(17))
self.layer.setNeedsDisplayIn(rect)
【讨论】:
此解决方法不适用于 NSView,您是否找到其他替代方法? 过去两年我一直在使用这种解决方法。它在 ios 上仍然可以正常工作。以上是关于CATiledLayer 显示以前的图块的主要内容,如果未能解决你的问题,请参考以下文章