iOS Custom Map Layer Example
A barebones demo app that demonstrates the use of some new MapKit functionality in iOS 4.0.:
The MKOverlay protocol and MKOverlayView class and how to use these to render custom tile layers a la Google Maps API. (i.e. Google Maps-compatible tile layers from Mapnik/Tilecache, gheat, etc.) Examples include tilesets from OpenStreetMap and MapBox.
(Caveat: the OpenStreetMap renders opaquely over the default Google layer, it does not replace it.)
I refactored django-gheat as a side project and I’ve been working on iOS development a bit lately and was seeking a slick way to plug the django-gheat demo tileserver into the iPhone. The Google Maps API just doesn’t have enough performance in the browser to make for a decent user experience.
Some conversation threads recommended combining a UIScrollView with CATiledLayer, but this seemed unwieldy to couple with the existing MapKit framework.
Lo and behold, iOS 4.0 added custom overlay functionality to MapKit, though I have not seen any mention or example of it’s use to date.
The code is generally commented thoroughly. I am not an expert in cartography, so my knowledge of map projections and some of the calculations within the code are to be taken with a grain of salt.
CustomOverlayView compensates for
[[UIScreen mainScreen] scale], or the iPhone 4’s pixel doubling.
The view applies the screen scale factor, creating a situation as if the screen were twice as large.
Because MapKit loads pixel-doubled tiles but maintains the same viewport,
CustomOverlayView renders tiles
of the next (or scale-appropriate) zoom level to maintain a one-to-one mapping with MapKit’s own tiles.
[MKOverlayView -canDrawMapRect…] and
[MKOverlayView -drawMapRect…] methods rely on asynchronously
downloading tiles as requested (by
-canDrawMapRect) into cache, and then using that cache in the
-drawMapRect method after the success callback notifies MapKit to try the tile again.