CATiledLayer 显示以前的图块
CATiledLayer shows previous tiles
使 CATiledLayer 支持的视图无效时,先前的图块仍然 "stuck" 并且未正确无效。
这似乎发生在视图无效时(在主线程上),而与此同时,图块渲染线程仍在处理以前版本的图块。不是缓存新版本的磁贴,而是缓存以前的版本。
CATiledLayer 支持的视图是 UIScrollView 的子视图并且是可缩放的。瓦片的渲染可能很昂贵,可以使用渲染线程 10 毫秒。
例子
演示此问题的示例代码:https://github.com/Q42/CATiledLayerBug
- 在 CATiledLayer 中,开始渲染所有红色方块(这大约需要 3 秒才能完成)
- 每个渲染步骤大约需要 10 毫秒
- 渲染期间(800 毫秒后),使完整视图无效:
tiledView.setNeedsDisplay()
- 开始渲染所有灰色方块(这又需要大约 3 秒)
- 两个瓷砖(随机?)保持红色,而不是变成灰色。
在此处查看 update
函数:https://github.com/Q42/CATiledLayerBug/blob/master/TiledLayerTest/ViewController.swift#L45
解决方法?
这似乎是 CATiledLayer
实现中的错误。由于我无法解决这个问题,有人知道解决此问题的好方法吗?
我已为此提交雷达:http://www.openradar.me/28648050
根据我添加到示例项目的一些进一步日志记录,我认为问题是这样的:
CATiledLayer
有两个绘制线程的渲染线程。如果在 draw(_: CGRect)
调用的执行期间调用了 setNeedsDisplay
,则 draw
调用的当前执行已完成并且结果被缓存。缓存值基于之前的 "data source"(本例中只是磁贴颜色),而不是更新后的数据源。
Apple 支持工程师为我提供了解决方法:
- 向 TiledView 添加一个
updateID
字段
- 添加
draw(_: CGRect)
调用的开始保存当前 updateID
- 当"data source"改变时,改变
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)
}
}
}
使 CATiledLayer 支持的视图无效时,先前的图块仍然 "stuck" 并且未正确无效。
这似乎发生在视图无效时(在主线程上),而与此同时,图块渲染线程仍在处理以前版本的图块。不是缓存新版本的磁贴,而是缓存以前的版本。
CATiledLayer 支持的视图是 UIScrollView 的子视图并且是可缩放的。瓦片的渲染可能很昂贵,可以使用渲染线程 10 毫秒。
例子
演示此问题的示例代码:https://github.com/Q42/CATiledLayerBug
- 在 CATiledLayer 中,开始渲染所有红色方块(这大约需要 3 秒才能完成)
- 每个渲染步骤大约需要 10 毫秒
- 渲染期间(800 毫秒后),使完整视图无效:
tiledView.setNeedsDisplay()
- 开始渲染所有灰色方块(这又需要大约 3 秒)
- 两个瓷砖(随机?)保持红色,而不是变成灰色。
在此处查看 update
函数:https://github.com/Q42/CATiledLayerBug/blob/master/TiledLayerTest/ViewController.swift#L45
解决方法?
这似乎是 CATiledLayer
实现中的错误。由于我无法解决这个问题,有人知道解决此问题的好方法吗?
我已为此提交雷达:http://www.openradar.me/28648050
根据我添加到示例项目的一些进一步日志记录,我认为问题是这样的:
CATiledLayer
有两个绘制线程的渲染线程。如果在 draw(_: CGRect)
调用的执行期间调用了 setNeedsDisplay
,则 draw
调用的当前执行已完成并且结果被缓存。缓存值基于之前的 "data source"(本例中只是磁贴颜色),而不是更新后的数据源。
Apple 支持工程师为我提供了解决方法:
- 向 TiledView 添加一个
updateID
字段 - 添加
draw(_: CGRect)
调用的开始保存当前updateID
- 当"data source"改变时,改变
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)
}
}
}