Deallocation while key value observers still registered (reverse geocoder)

mlewis54 picture mlewis54 · Feb 21, 2011 · Viewed 17.2k times · Source

When my view goes away I get the following message:

An instance 0x1c11e0 of class MKAnnotationView was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:

( Context: 0x0, Property: 0x1e98d0> )

The code that defines and starts the reverse geocoding is:

geo=[[MKReverseGeocoder alloc] initWithCoordinate:droppedAt];
        geo.delegate=self;
        [geo start];

I have tried setting geo.delegate to nil right before the I dismiss the view. That would be too easy. I have also tried:

for (id <MKAnnotation> annotation in mvMap.annotations) {
    [[mvMap viewForAnnotation:annotation] removeObserver:self forKeyPath:@"selected"];
}

Which throws an error that says:

* Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer for the key path "selected" from because it is not registered as an observer.

My view for annotation code is:

-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    MKAnnotationView *aView;

    aView=(MKAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:annotation.title];
    if (aView==nil) 
        aView=[[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotation.title] autorelease];
    else
        aView.annotation=annotation;
    [aView setImage:[UIImage imageNamed:selIcon]];
    aView.canShowCallout=TRUE;
    aView.draggable=YES;
    return aView;
}

I'm sort of pushing buttons and flipping switches here while spinning in. Any idea of what I can do here?

Answer

Olie picture Olie · Mar 30, 2011

You may have multiple issues, here. For every delegate you set up, you should clear it at dealloc. For every observer you set up, you should clear that, same with Notifications, etc.

So your dealloc should have (typed in web browser, you may have to adjust):

- (void) dealloc
{
     [[NSNotificationCenter defaultCenter] removeObserver: self];
     for (id <MKAnnotation> annotation in mvMap.annotations)
     {
          // remove all observers, delegates and other outward pointers.
          [[mvMap viewForAnnotation:annotation] removeObserver: self forKeyPath: path];
     }

     gel.delegate = nil;
     // etc., your other stuff
     [super dealloc];  // Only in non-ARC legacy code.  Modern stuff skips this.
}

Go through your setup (likely in viewDidLoad) and make sure that you un-do everything that you did in there. Specifically anything that triggers a callback.