Reputation: 127
I have MKMapView with MKUserTrackingModeFollowWithHeading. But something changes the userTrackingMode to MKUserTrackingModeFollow or None, so I implemented,
- (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated
{
if ([CLLocationManager locationServicesEnabled]) {
if ([CLLocationManager headingAvailable]) {
[self.myMapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:NO];
}else{
[self.myMapView setUserTrackingMode:MKUserTrackingModeFollow animated:NO];
}
}else{
[self.myMapView setUserTrackingMode:MKUserTrackingModeNone animated:NO];
}
}
Everything is fine but everytime I zoom in the map to most detail level, the app causes EXC_BAD_ACCESS in the line setUserTrackingMode:MKUserTrackingModeFollowWithHeading shown above.
What should I do to avoid crashing? I don't want to use MKUserTrackingBarButtonItem if possible.
The other part of the mapViewController is below.
- (void)dealloc
{
self.myMapView.delegate = nil;
}
- (void)viewWillDisappear:(BOOL)animated
{
if ([CLLocationManager locationServicesEnabled]) {
self.myMapView.showsUserLocation = NO;
[_locManager stopUpdatingLocation];
if ([CLLocationManager headingAvailable]) {
[_locManager stopUpdatingHeading];
}
}
[super viewWillDisappear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
if ([CLLocationManager locationServicesEnabled]) {
self.myMapView.showsUserLocation = YES;
[_locManager startUpdatingLocation];
if ([CLLocationManager headingAvailable]) {
[self.myMapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:NO];
[_locManager startUpdatingHeading];
}else{
[self.myMapView setUserTrackingMode:MKUserTrackingModeFollow animated:NO];
}
}else{
[self.myMapView setUserTrackingMode:MKUserTrackingModeNone animated:NO];
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.myMapView.delegate = self;
[self.myMapView setFrame:self.view.frame];
self.locManager = [CLLocationManager new];
[self.locManager setDelegate:self];
[self.locManager setDistanceFilter:kCLDistanceFilterNone];
[self.locManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locManager setHeadingFilter:3];
[self.locManager setHeadingOrientation:CLDeviceOrientationPortrait];
}
Any kind of advice appreciated. Thank you in advance.
I upload minimum sample code to github.
Upvotes: 3
Views: 2672
Reputation: 437372
I might suggest trying to defer the setting of the tracking mode, e.g.:
- (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated
{
dispatch_async(dispatch_get_main_queue(),^{
if ([CLLocationManager locationServicesEnabled]) {
if ([CLLocationManager headingAvailable]) {
[self.myMapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:NO];
}else{
[self.myMapView setUserTrackingMode:MKUserTrackingModeFollow animated:NO];
}
}else{
[self.myMapView setUserTrackingMode:MKUserTrackingModeNone animated:NO];
}
});
}
I might also suggest checking to make sure the mode
isn't already what you want, eliminating a redundant setUserTrackingMode
:
- (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated
{
MKUserTrackingMode newMode = MKUserTrackingModeNone;
if ([CLLocationManager locationServicesEnabled]) {
if ([CLLocationManager headingAvailable]) {
newMode = MKUserTrackingModeFollowWithHeading;
}else{
newMode = MKUserTrackingModeFollow;
}
}
if (mode != newMode)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.myMapView setUserTrackingMode:newMode animated:YES];
});
}
}
You could also combine that with scrollEnabled
(which should prevent the user from incidentally initiating a changing of the tracking mode).
Upvotes: 5