I have an MKMapView that’s supposed to track the user’s location using a custom view (not the blue dot). In order to substitute this view for the blue dot, I return it thusly:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (annotation == [mapView userLocation])
{
return userLocationView;
}
}
To initialize tracking, I call
[mapView setShowsUserLocation: YES];
[mapView setUserTrackingMode: MKUserTrackingModeFollow animated: NO];
[mapView setDelegate: self];
As would be expected, -mapView:didUpdateUserLocation: gets called once when the app loads. Unfortunately, it’s never called again unless I change -mapView:viewForAnnotation: to have the following implementation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (annotation == [mapView userLocation])
{
return nil;
}
}
With these changes, the map loads the blue dot as the indicator of the user’s location, and -mapView:didUpdateUserLocation: gets called frequently, as would be expected.
Is there some sort of mutual exclusivity for tracking users’ locations and have a custom user location view? How can I make both happen?
Source
This project demonstrates this issue. https://dl.dropbox.com/u/2338382/MapKitFuckery.zip
Bug
This is most likely a bug, which I’ve filed as a radar. In the interim, the accepted answer should prove sufficient. However, it bears noting that I had to give up entirely on [mapView userLocation] and [mapView showsUserLocation], in favor of simply a custom annotation and the CLLocationManager.
Instead of relying on the map view’s location updates, start a
CLLocationManager, set itsdelegateand wait for-locationManager:didUpdateToLocation:fromLocation:(in iOS 5 and lower) or-locationManager:didUpdateLocations:(iOS 6). You will get much more reliable and plentiful information than using the map view’s delegate methods. You probably know the way to do this, but here it is:I had a look at the delegate calls that come in to the mapView’s delegate, and returning anything other than
nilstops calls to-mapView:didUpdateUserLocation:, like you said. Here are the calls in the order they arrive:Presumably the
MKUserLocationobject, not theMKMapViewis the object responsible for calling the delegate with update calls. If you check the status ofshowsUserLocationandmapView.userLocation, they both look fine:returns
1and a non-nil object (1 <MKUserLocation: 0x1e02e580>). Maybe themapViewqueries itsuserLocationobject to get the current location, then sends it to the delegate. If that object has gone, it won’t work.It’s a bit strange, but like I said, you’ll get better updates from a
CLLocationManager‘s updates.