There is a problem with MapKit on iOS - map sometimes fails to load, another time it loads partially, displaying plain grid for a tile which failed to load. The problem happens systemwide in every app that uses MapKit, even in Apple Maps app. The problem happens on both iPhones (6+) and iPads (iPad Air, iPad Air 2, iPad Mini) and a range of iOS versions (9.0, 9.0.2, 9.2.1). Furthermore it seems to happen more often when map zoom is high. The problem is very hard to reproduce, because it looks to happen randomly, persists on affected device for some time and suddenly disappears.
I managed to analyse network traffic and found possible reason of this strange behaviour. Network requests associated with missing tiles fail with HTTP status code 410 and empty content:
GET http://gspe19.ls.apple.com/tile.vf?flags=1&style=13&size=2&scale=0&v=11040322&z=15&x=17923&y=10756&sid=SOME_SID_1&accessKey=SOME_ACCESS_KEY_1 <- 410 GET http://gspe19.ls.apple.com/tile.vf?flags=1&style=20&size=2&scale=0&v=11040322&z=15&x=17923&y=10756&sid=SOME_SID_1&accessKey=SOME_ACCESS_KEY_1 <- 410 ...
'v' parameter seems to be a map version number and grow with time. It looks that the version number can change after a 'geo_manifest' network call, which happens from time to time:
After downloading new geo_manifest, version number becomes valid once again and every tile request ends successfully with HTTP status code 200:
GET http://gspe19.ls.apple.com/tile.vf?flags=1&style=13&size=2&scale=0&v=11040529&z=15&x=17923&y=10756&sid=SOME_SID_2&accessKey=SOME_ACCESS_KEY_2 <- 200 GET http://gspe19.ls.apple.com/tile.vf?flags=1&style=20&size=2&scale=0&v=11040529&z=15&x=17923&y=10756&sid=SOME_SID_2&accessKey=SOME_ACCESS_KEY_2 <- 200 ...
I used an lldb to confirm, that a stale geo_manifest is the reason of 410 responses. I ran an arbitrary app on device that showed the symptoms using Xcode. Some tiles were missing on a MKMapView, and 410 responses appeared in network traffic. I closed the map, paused execution with lldb, executed a private GeoService framework method that seemed to force geo_manifest update:
(lldb) po [[GEOResourceManifestManager sharedManager] forceUpdate]
After resuming execution, geo_manifest update request appeared in network traffic. After opening map view, successful tile responses appeared and map was fully loaded. Looks like com.apple.geod daemon itself fails to query for new geo_manifest from time to time. Because the problem is so ephemeral, it was impossible to find any com.apple.geod errors in device console logs.
Following questions arise: why do com.apple.geod, GeoServices or MapKit not try to query for new geo_manifest when tile request results in 410 response? Is that a known issue? Does Apple plan to fix this in future iOS versions?