MKOverlayRenderer.setNeedsDisplay Causes MKTileOverlayRenderer To Re-Render Tiles

Last update: Mar 16, 2022

MKOverlayRenderer.setNeedsDisplay Causes MKTileOverlayRenderer To Re-Render Tiles

Bug Report ID

FB9957545

Note: this is still broken as of iOS 15 (Xcode 13.3).

Notes

This demo app exposes a MapKit bug that re-renders MKTileOverlayRenderer tiles when:

  • another MKOverlayRenderer calls any of the setNeedsDisplay methods.
  • an overlay is added to the map (e.g. simple MKPolyline + MKPolylineRenderer).

Here are the main players in this demo:

  • MapViewController:
    • Basic MKMapView host view controller and MKMapDelegate.
    • Contains two toolbar buttons to add and remove a GridOverlay.
  • A GridOverlay renders using a DelayedGridOverlayRenderer.
  • A DelayedGridOverlayRenderer is a simple MKOverlayRenderer that calls the setNeedsDisplay function "later".
    • Simulates asynchronously generating/ loading tiles (but for simplicity just renders a box around the tile).

Feedback ID: FB9957545

Demo showing the "flickering" bug

Bug

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    switch overlay {
    case let tileOverlay as MKTileOverlay:
        // Note: Replace the `MKTileOverlayRenderer` with the `HackTileOverlayRenderer` to stop re-drawing madness.
        return MKTileOverlayRenderer(tileOverlay: tileOverlay)
    case is GridOverlay:
        return DelayedGridOverlayRenderer()
    default:
        return MKOverlayRenderer(overlay: overlay)
    }
}

Demo that includes a hack to eliminate the "flickering" bug

Fixed

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    switch overlay {
    case let tileOverlay as MKTileOverlay:
        // Note: Replace the `HackTileOverlayRenderer` with the `MKTileOverlayRenderer` to expose re-drawing madness.
        return HackTileOverlayRenderer(tileOverlay: tileOverlay)
    case is GridOverlay:
        return DelayedGridOverlayRenderer()
    default:
        return MKOverlayRenderer(overlay: overlay)
    }
}

Possible workaround (aka super-duper hack)

It turns out that simply subclassing MKTileOverlayRenderer, overriding draw(_:zoomScale:in), and calling super resolves the re-drawing problem. I can't explain why. Possible ObjC runtime shenanigans?

Here's the full hack-workaround.

import MapKit

final class HackTileOverlayRenderer: MKTileOverlayRenderer {

    override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
        super.draw(mapRect, zoomScale: zoomScale, in: context)
    }
}

Other

This sample demo uses OpenStreetMap tiles to help demonstrate the MapKit bug. https://www.openstreetmap.org/copyright

GitHub

https://github.com/briancoyner/MKOverlayRendererBug
You might also like...

Render Markdown text in SwiftUI, preview based on the Marked implementation

Render Markdown text in SwiftUI, preview based on the Marked implementation

Markdown Render Markdown text in SwiftUI. It is a preview based on the Marked implementation. swiftui-markdown.mov Installation You can add MarkdownUI

Jun 22, 2022
Related tags
Interactive, thoroughly customizable maps in native Android, iOS, macOS, Node.js, and Qt applications, powered by vector tiles and OpenGL

Mapbox GL Native A C++ library that powers customizable vector maps in native applications on multiple platforms by taking stylesheets that conform to

Jun 23, 2022
An iOS library to natively render After Effects vector animations
An iOS library to natively render After Effects vector animations

Lottie for iOS, macOS (and Android and React Native) View documentation, FAQ, help, examples, and more at airbnb.io/lottie Lottie is a mobile library

Jun 21, 2022
add text(multiple line support) to imageView, edit, rotate or resize them as you want, then render the text on image
add text(multiple line support) to imageView, edit, rotate or resize them as you want, then render the text on image

StickerTextView is an subclass of UIImageView. You can add multiple text to it, edit, rotate, resize the text as you want with one finger, then render the text on Image.

Jun 1, 2022
Demo of using Metal to render EDR / HDR content on iOS platform
Demo of using Metal to render EDR / HDR content on iOS platform

MetalEDR-iOS Demo of using Metal to render EDR/HDR content on iOS platform. How it works This demo uses a hack to activate EDR display on iOS platform

May 27, 2022
SwiftUI library to easily render diagrams given a tree of objects. Similar to ring chart, sunburst chart, multilevel pie chart.
SwiftUI library to easily render diagrams given a tree of objects. Similar to ring chart, sunburst chart, multilevel pie chart.

Swift Sunburst Diagram Sunburst diagram is a library written with SwiftUI to easily render diagrams given a tree of objects. Similar to ring chart, su

Jun 17, 2022
Render Markdown text in SwiftUI
Render Markdown text in SwiftUI

MarkdownUI MarkdownUI is a library for rendering Markdown in SwiftUI, fully compliant with the CommonMark Spec. Supported Platforms You can use the Ma

Jun 18, 2022
A ninepatch image render framework for iOS and MacOS
A ninepatch image render framework for iOS and MacOS

NinePatchKit NinePatch image parser and render framework for iOS & macOS Multilingual translation Chinese README Main Features parse png's binary data

Jun 8, 2022
Simple calculation to render cheap water effects.
Simple calculation to render cheap water effects.

Water Simple calculation to render cheap water effects. This simple project demonstrates : how to use Metal draw compute shader, or known as 'kernal f

May 18, 2022
Swift package that uses WebKit to render PDF files from URLs

Swift package for generating a PDF file from a URL (rendered by WebKit)

Feb 25, 2022
Render Markdown text in SwiftUI
Render Markdown text in SwiftUI

Render Markdown text in SwiftUI. It is a preview based on the Marked implementation

Jun 21, 2022