iOS 13.2 从 MapKit 中删除覆盖导致地图闪烁

iOS 13.2 removing overlay from MapKit causing map to flicker

我在我的应用程序中使用 mapKit,我有几个使用叠加层渲染图形的函数。 现在,随着 iOS 13.2 更新,当我移动地图(使用任何方法)时,移除单个叠加层并在地图移动时重新绘制叠加层的功能 - 导致地图中的所有图形闪烁 - 就好像它们是全部重绘。 移动地图的方法之一是通过 locationManager 'didUpdateLocations'。

我不会 post 代码,因为代码被拆分成许多子函数,所有子函数都以不同的组合调用。 但是我已经测试了很多方法来验证图形是否仅通过添加或删除覆盖的单一操作而闪烁。我已经评估了添加或删除的叠加层以验证它只是一个小图形 (MKPolyline) - 而不是地图上 graphics/overlays 的集合。

所以基本上,addOverlay 函数似乎有问题 - 重绘所有叠加层..,或类似这样...

还有其他人在使用 iOS13.2 时遇到这个问题吗?

同样的事情发生在我身上。从 iOS13.2 开始,添加叠加层(任何类型,如 tileoverlay、polyline)将导致所有叠加层刷新、闪烁。

所以,我将所有叠加层添加到地图,并将渲染器的 alpha 更改为 hide/show 它们,这是一种临时解决方案。

类似的事情也发生在我身上。我有一个几个月没有更改的应用程序,但是当我升级到 iOS 13.2 时,它开始出现问题。该应用程序有一个呈现 MKTileOverlays 的 mapView。围绕中心蓝点的 2x2 瓷砖网格在所有缩放级别以每秒一次的速度连续闪烁。当屏幕闪烁时,我能够捕捉到屏幕(在 iPhone 上),我可以看到它在更高的缩放级别上显示了许多图块。

在下图中,地图的缩放级别为 14。我用绿色勾勒出 2x2 闪烁的图块。当它闪烁时,会出现几个缩放级别 16(橙色轮廓)和缩放级别 17(紫色轮廓)的图块。

只有当我之前在这些区域中放大到该级别时,才会出现更高缩放级别的图块。否则,2x2 闪烁的网格为空。

更新:

这是我在 2019 年 12 月 5 日从 Apple Developer Technical Support 收到的回复...

What you’re seeing is a known bug in MapKit. I wanted to pass along some additional information to help reduce how often you may see this in your real app. A common pattern that some apps use in the MKMapView usage is to do frequent updates to their overlays, such as removing all overlays at once, and then adding some subset (or all) of them back. In particular, if this is done to the hot code paths for user driven events, such as pinching and zooming the map, the blinking tile behavior is exacerbated.

In the case of the sample [provided by P. Stern], this is the location manager’s location update, which can be called at 60 Hertz in some circumstances. You can do something like a distance comparison and only update the polyline if there’s a significant enough change in the coordinate since the last time you replaced the polyline to be meaningful to the user for your trail use case. Applying this to your real app, please audit the points where you add and remove overlays, and try to reduce the number of times those methods get called. This won’t eliminate the tile blinking problem, but may reduce its frequency as a way to mitigate the effects of our issue.

When looking at your overlays, also consider why you need to add and remove overlays from the map, and if there are opportunities to do so in bulk, but rarely. Another common pattern I see often is trying to keep track of the overlays to keep memory usage down, and continually updating the overlays added to the map to reflect only those relevant to the user’s location or visible map rectangle. However, the MKOverlay objects themselves are usually not large, because they are only a coordinate and a bit of data, so the memory saved by these techniques is often in the kilobyte to low megabyte range, which isn’t much improvement when an app with a map needs 100 MB just for the map, let alone the rest of the app’s data and view controllers.

最终更新:

Apple 似乎已经解决了这个问题。我正在使用 iOS 13.7 (Xcode 12) 并且不再发生闪烁。正如 Zifigo 指出的那样,它可能已在 iOS 13.4 中修复。

我找到了两个必要条件

  1. 使用 MKTileOverlay 作为自定义图块
  2. 删除 MKOverlay 对象

iOS 13.4 解决了我的应用程序的问题 - 终于!

添加叠加层会导致重新加载所有叠加层,从而导致闪烁。要最大限度地减少闪烁,请尽量减少叠加添加的数量。不要用新的叠加层替换叠加层,而是实现一个叠加层渲染器,观察重要的叠加层属性并在需要时重新绘制叠加层使旧路径无效。

我在 iOS 15.

中看到了这个问题

显然这个解决方案并不理想,但它适用于我们的用例并防止闪烁。也许它会节省别人一些时间。

mapView.addOverlay(currentLine)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) {
    self.mapView.removeOverlay(newLine)
}