1

I need some help with an app i'm making using MapKit

I'm struggling with the didUpdateUserLocation: - it keeps randomly crashing the app. When I comment out all of the code it works perfectly but this isn't a suitable situation. I've been fiddling around with it all but still no real success.

Here's my code

-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
    NSLog(@"update loc");
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 250.0, 250.0);//MKCoordinateRegionMake(userLocation.coordinate, mapView.region.span);
    if (first) {
        region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 250.0, 250.0);
        first = false;
    }
    if (!CLLocationCoordinate2DIsValid(userLocation.coordinate)) {
        //do nothing, invalid regions
        NSLog(@"co-ord fail");
    } else if (region.span.latitudeDelta <= 0.0 || region.span.longitudeDelta <= 0.0) {
        NSLog(@"invalid reg");
    } else {
        [mapView setRegion:region animated:NO];
    }
} 

The app never hits "co-ord fail" or "invalid reg" so I don't really know what the problem is since I set the values myself.

The problem usually occurs when the nib for the Map is closed and it has dealloced the view.

I have seen some other suggestions but haven't been confident about their work. Ideally I'd like to use mapView.region.span so to maintain the zoom levels

Many Thanks, James

jr19
  • 92
  • 7
  • What is the exact error message when it crashes? –  Jan 09 '12 at 03:43
  • Sorry hadn't seen this - bit of a noob here. There wasn't a specific error code when in debug but in crash logs the explanation for the crashing would be [MapKit mapView:didUpdateUserLocation:]. I have fixed the problem using guidance from Daryl's answer. Thanks for your reply! – jr19 Jan 09 '12 at 15:29

2 Answers2

1

Watch out that if an App that was suspended a short while, on resume the

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation 

delegate receives as the first userLocation (0.0,0.0) as latitude,longitude! I think that is a bug.. Check:

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
NSLog( @"userLocation:(%p) %@",userLocation,userLocation);
NSLog( @"userLocation.location:(%p) %@",userLocation.location,userLocation.location);
NSLog( @"userLocation.coordinate: %f,%f valid:%d",userLocation.coordinate.latitude,userLocation.coordinate.longitude,  CLLocationCoordinate2DIsValid(userLocation.coordinate));
NSLog( @"userLocation.location.coordinate: %f,%f valid: %d",userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude, CLLocationCoordinate2DIsValid(userLocation.location.coordinate));

Result:

userLocation:(0x193fc0) <MKUserLocation: 0x193fc0>
userLocation.location:(0x0) (null)
userLocation.coordinate: -180.000000,-180.000000 valid:0
userLocation.location.coordinate: 0.000000,0.000000 valid: 1

Odd that 0,0 is produced from userLocation.location.coordinate while userLocation.location is nil, resulting in a valid coordinate, even!

Indeed the check on userLocation.location being nil seems best.

RickJansen
  • 1,615
  • 18
  • 24
  • Thanks for your comment, this is covered by the CLLocationCoordinate2DIsValid() check – jr19 Aug 15 '12 at 07:03
  • I don't think CLLocationCoordinate2DIsValid catches 0,0 (see above) – RickJansen Aug 15 '12 at 17:11
  • It's better to use `if (userLocation.location == nil)` instead of checking for 0,0 which is technically a valid coordinate. –  Aug 15 '12 at 17:14
  • Ah, I am (was) using userLocation.location.coordinate, not userLocation.coordinate! Now I'm confused, MKUserLocation has a property "location", which has itself a property "coordinate". MKUserLocation has a coordinate itself too, which it inherited from MKAnnotation... Investigating what the difference is... – RickJansen Aug 15 '12 at 17:42
  • In Objective-C, when you send messages to a nil object, you get 0 back (instead of a crash) which is why the NSLog of location.coordinate is misleading. However, I don't believe this is related to the OP's issue. –  Aug 15 '12 at 18:02
  • Could it be that userLocation.coordinate is derived by the system the same way from a nil userLocation.location...? In that case it'd be best to not use userLocation.coordinate in these circumstances, but always userLocation.location.coordinate – RickJansen Aug 15 '12 at 18:10
  • I don't know the system's internal logic but I agree that it is a bug that this delegate method gets called even if location is nil. What I do is first check if userLocation.location is not nil and only then use userLocation.coordinate (or userLocation.location.coordinate). If userLocation.location is not nil, the coordinate property has valid data. Related: http://stackoverflow.com/questions/9680576/is-this-a-bug-with-mkmapkitdelegate-mapviewdidupdateuserlocation –  Aug 15 '12 at 18:25
-1

The problem usually occurs when the nib for the Map is closed and it has dealloced the view.

   [mapView setRegion:region animated:NO];

Well isn't that your problem then?

This is why we have dependency inversion patterns like Observer/Listener.

Instead of fiddling around with the view directly with your CLLocationManager delegate, use NSNotification to alert subscribing views (such as your MapView) that it should update. If the MapView has been dealloced it won't do anything.

Daryl Teo
  • 5,394
  • 1
  • 31
  • 37
  • -(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation is part of the delegate call so it is only called by MKMapView, so I don't think that the NSNotification was the right way to go. You did however get me thinking (from your correct idea that the MapView will have been released and I should check the nob hash't been released) and I realised I should've released the MapView from dealloc. That seems to have provided a solution. Thanks for your guidance!! – jr19 Jan 09 '12 at 11:47