MKOverlayRenderer.setNeedsDisplay Causes MKTileOverlayRenderer To Re-Render Tiles

Related tags

Maps mapkit
Overview

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

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

Owner
Brian Coyner
Mobile Architect, Technical Leader
Brian Coyner
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

Mapbox 4.2k Jan 9, 2023
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

Airbnb 23.6k Dec 31, 2022
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.

Textcat 478 Dec 17, 2022
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

Wutian 38 Oct 24, 2022
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

Ludovic Landry 494 Dec 19, 2022
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

Guille Gonzalez 916 Jan 8, 2023
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

Theo 14 Sep 30, 2022
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

Xue Yu 381 Sep 20, 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)

aaronland 1 Feb 25, 2022
Render Markdown text in SwiftUI

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

小弟调调™ 26 Dec 20, 2022