【问题标题】:CATiledLayer shows previous tilesCATiledLayer 显示以前的图块
【发布时间】:2017-02-14 22:21:35
【问题描述】:

当使由 CATiledLayer 支持的视图无效时,前一个图块仍然“卡住”并且未正确无效。

这似乎发生在视图无效时(在主线程上),而与此同时,瓷砖渲染线程仍在处理先前版本的瓷砖。不是缓存新版本的磁贴,而是缓存以前的版本。

CATiledLayer 支持的视图是 UIScrollView 的子视图,并且是可缩放的。瓦片的渲染可能会很昂贵,并且可以使用渲染线程 10 毫秒。

示例

演示此问题的示例代码:https://github.com/Q42/CATiledLayerBug

  1. 在 CATiledLayer 中,开始渲染所有红色图块(这大约需要 3 秒才能完成)
  2. 每个渲染步骤大约需要 10 毫秒
  3. 在渲染期间(800ms 后),使完整视图无效:tiledView.setNeedsDisplay()
  4. 开始渲染所有灰色图块(这同样需要大约 3 秒)
  5. 两个图块(随机?)保持红色,而不是变成灰色。

在此处查看update 函数:https://github.com/Q42/CATiledLayerBug/blob/master/TiledLayerTest/ViewController.swift#L45

解决方法?

这似乎是CATiledLayer 的实现中的一个错误。由于我无法解决这个问题,有人知道解决此问题的好方法吗?

我已经为此提交了一个雷达:http://www.openradar.me/28648050

【问题讨论】:

    标签: ios swift catiledlayer


    【解决方案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 上仍然可以正常工作。
    猜你喜欢
    • 2010-11-11
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 2011-11-13
    相关资源
    最近更新 更多