I , too, got frustrated with this extremely annoying bug.
I have a deadline just around the corner, so I can't spend a lot of time trying to implement a workaround.
I had managed to get it to stay in MKUserTrackingModeFollowWithHeading at max zoom, but the User Location annotation "pin" still jittered around quite heavily, and in some edge cases, it was still canceling back into MKUserTrackingModeFollow.
What I did, initially, was to force a correction using BOOL flags in the regionDidChangeAnimated: delegate method, like so:
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
NSLog(@"regionWillChangeAnimated:");
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
NSLog(@"regionDidChangeAnimated:");
[self forceCorrectUserTrackingMode];
}
- (void)forceCorrectUserTrackingMode {
if (shouldFollowWithHeading == YES && ([mapView userTrackingMode] != MKUserTrackingModeFollowWithHeading) ) {
NSLog(@"FORCE shouldFollowWithHeading! - setUserTrackingMode:MKUserTrackingModeFollowWithHeading");
[self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:YES];
} else if (shouldFollowWithHeading == NO && ([mapView userTrackingMode] != MKUserTrackingModeNone) ) {
NSLog(@"FORCE should NOT FollowWithHeading - setUserTrackingMode:MKUserTrackingModeNone");
[self.mapView setUserTrackingMode:MKUserTrackingModeNone animated:YES];
}
}
This actually got me pretty close, but it wasn't reliable enough, and like I said, I had to think about prioritizing other features for my deadline, so this is what I ended up doing:
First, I grabbed this code for a zoom category on MKMapKit: http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/
Next, I included this method that a visitor provided in that blog's comments:
- (int) getZoomLevel {
return 21 – round(log2(mapView.region.span.longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * mapView.bounds.size.width)));
}
Finally, a little trial and error testing the zoom levels vs. the occurrence of the bug led me to the following "workaround":
CLLocationCoordinate2D userLocation_CenterCoordinate = CLLocationCoordinate2DMake([locationManager location].coordinate.latitude, [locationManager location].coordinate.longitude);
int currentZoomLevel = [MKMapView getZoomLevelForMapView:mapView];
int newZoomLevel = 17;
if (currentZoomLevel > 17) {
NSLog(@"Adjusting mapView's zoomLevel from [%d] to [%d], also centering on user's location", currentZoomLevel, newZoomLevel);
[mapView setCenterCoordinate:userLocation_CenterCoordinate zoomLevel:newZoomLevel animated:NO];
} else {
NSLog(@"Centering on user's location, not adjusting zoom.");
[mapView setCenterCoordinate:userLocation_CenterCoordinate animated:NO];
}