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 显示以前的图块的主要内容,如果未能解决你的问题,请参考以下文章

在 CATiledLayer 中预加载/预显示图块?

osmdroid - 显示更大的图块

CATiledLayer 在绘制内容之前消隐图块

OpenLayers 3:重新加载失败的图块

MKTileOverlay:如何重新加载特定的图块或区域

如何平铺 UIWebView?