I'm attempting to save a thumbnail of a mapview when a user taps save when an annotation has been selected. The problem occurs when the user has not zoomed in on that annotation yet, so the close zoom level has not been loaded.
This is what I'm doing after the user taps save:
However when the image is saved, and the view is dismissed the result image saved actually has not finished loading, as I still see an unloaded map with gridlines as shown below:
My question is, how can I ensure the map is finished loading AND finished displaying before I save this thumbnail?
Update: iOS7 has a new delegate which may have fixed this problem. I have not confirmed one way or the other yet.
- (void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered
Pre iOS6 support:
mapViewDidFinishLoadingMap
: appears to be unreliable. I notice that it is sometimes not called at all, especially if the map tiles are already cached, and sometimes it is called multiple times.
I notice that when it is called multiple times the last call will render correctly. So I think you can get this to work if you set up a 2 second timer after the user taps save. Disable interactions so that nothing else can happen, and enable user interactions when the timer goes.
If mapViewDidFinishLoadingMap
gets called reset the timer again for 2 seconds in the future. When the timer finally goes off, get the snapshot of the map and it should be correct.
You will also want to consider the other callbacks such as mapViewDidFailLoadingMap
. Also test this on a noisy connection, since 2 seconds may not be long enough if it takes a long time to fetch the tiles.
- (void)restartTimer
{
[self.finishLoadingTimer invalidate];
self.finishLoadingTimer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(mapLoadingIsFinished)
userInfo:nil
repeats:NO];
}
- (void)userClickedSave
{
assert(self.saving == NO);
if (self.saving == NO) {
self.saving = YES;
assert(self.finishLoadingTimer == nil);
self.view.userInteractionEnabled = NO;
[self restartTimer];
}
}
- (void)mapLoadingIsFinished
{
self.finishLoadingTimer = nil;
[self doSnapshotSequence];
self.saving = NO;
self.view.userInteractionEnabled = YES;
}
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView
{
if (self.saving) {
[self restartTimer];
}
}
If developing for iOS7 the best delegate to use is: mapViewDidFinishRenderingMap:fullyRendered:
mapViewDidFinishRenderingMap:fullyRendered
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With