2

I am getting a runtime error at the point marked below? How to call MKTileOverlay "url" function from subclass? getting EXC_BAD_INSTRUCTION?

Basically want to show custom tiles in some places, but when not available drop back to standard Apple map tiles.

class GCMapOverlay : MKTileOverlay {
    override func url(forTilePath path: MKTileOverlayPath) -> URL {
        // Get local custom map tile if available
        let optionalUrl = Bundle.main.url(
            forResource: "\(path.y)",
            withExtension: "png",
            subdirectory: "tiles/\(path.z)/\(path.x)",
            localization: nil)
        NSLog("tiles/\(path.z)/\(path.x)/\(path.y)")

        guard let url = optionalUrl else {
            // Local tile not available - want to drop back to an apple maps tile (as if MKTileOverlay wasn't subclassed)
            return super.url(forTilePath: path)    // <== RUNTIME ERROR: NetworkLoad (10): EXC_BAD_INSTRUCTION
        }

        // Local tile available so return
        return url
    }
}

in my controller

func setupTileRenderer() {
    let overlay = GCMapOverlay()
    overlay.canReplaceMapContent = true
    mapView.addOverlay(overlay, level: .aboveLabels)
    tileRenderer = MKTileOverlayRenderer(tileOverlay: overlay)
}
Greg
  • 34,042
  • 79
  • 253
  • 454

2 Answers2

2

I've never used MKTileOverlay but the documentation for url(forTilePath:) states:

The default implementation of this method uses the template string you provided at initialization time to build a URL to the specified tile image.

And the MKTileOverlay class provides the initializer:

init(urlTemplate:)

But when you create an instance of GCMapOverlay, you don't use that initializer.

Replacing:

let overlay = GCMapOverlay()

with:

let overlay = GCMapOverlay(urlTemplate: someAppropriateTemplate)

or overriding the urlTemplate property in your subclass should resolve your issue when calling super.url(forTilePath:).

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • thanks - the issue is I am not sure what the "default" urlTemplate actually is for standard operation of maps, and how to get this? For example I do now how to fall back to OpenMaps, as I know how to specify the URL template, however I don't know the equivalent for IOS maps. Or even if this approach (within the GCMapOveral class) can actually be used to solve my requirement? – Greg May 03 '19 at 02:35
2

Remove overlay.canReplaceMapContent = true and change your guard statement so it loads a clear 256x256 tile.

guard let url = optionalUrl else {
    return Bundle.main.url(forResource: "emptyTile", withExtension: "png")!
}

Since all of your custom tiles are already stored locally they will be immediately loaded over the default Apple tiles which makes canReplaceMapContent unnecessary.

Make sure your custom tiles don't have alpha in them otherwise the Apple tile will be visible below.

Casey
  • 6,531
  • 24
  • 43