Brian Toth
Brian Toth

Reputation: 549

MKMapAnnotationManager not removing itself as observer for MKAnnotation

I'm still working on this, but figured it was worth asking about:

I have a class that conforms to the MKAnnotation protocol called AMAnnotation. This class also implements setCoordinate:

- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate
{
    NSLog(@"%@ %@", self, NSStringFromSelector(_cmd));
    _coordinate = newCoordinate;
}

I can successfully add the annotation to a map and I can call setCoordinate: and the pin will move on the map. But there's a problem. Sometimes, when the map gets deallocated, the program will pause on NSKVODeallocateBreak with the following message:

An instance 0x608000a626c0 of class AMAnnotation 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:
<NSKeyValueObservationInfo 0x60800045ca70> (
<NSKeyValueObservance 0x600000ac0460: Observer: 0x60800038ead0, Key path: coordinate, Options: <New: NO, Old: YES, Prior: YES> Context: 0x0, Property: 0x60000045fad0>
<NSKeyValueObservance 0x600000ac0460: Observer: 0x60800038ead0, Key path: coordinate, Options: <New: NO, Old: YES, Prior: YES> Context: 0x0, Property: 0x60000045fad0>
<NSKeyValueObservance 0x600000ac0460: Observer: 0x60800038ead0, Key path: coordinate, Options: <New: NO, Old: YES, Prior: YES> Context: 0x0, Property: 0x60000045fad0>
<NSKeyValueObservance 0x600000ac0460: Observer: 0x60800038ead0, Key path: coordinate, Options: <New: NO, Old: YES, Prior: YES> Context: 0x0, Property: 0x60000045fad0>
<NSKeyValueObservance 0x600000ac0460: Observer: 0x60800038ead0, Key path: coordinate, Options: <New: NO, Old: YES, Prior: YES> Context: 0x0, Property: 0x60000045fad0>
<NSKeyValueObservance 0x600000ac0460: Observer: 0x60800038ead0, Key path: coordinate, Options: <New: NO, Old: YES, Prior: YES> Context: 0x0, Property: 0x60000045fad0>
<NSKeyValueObservance 0x600000ac0460: Observer: 0x60800038ead0, Key path: coordinate, Options: <New: NO, Old: YES, Prior: YES> Context: 0x0, Property: 0x60000045fad0>
<NSKeyValueObservance 0x600000ac0460: Observer: 0x60800038ead0, Key path: coordinate, Options: <New: NO, Old: YES, Prior: YES> Context: 0x0, Property: 0x60000045fad0>
)

I don't add any observers myself, so I overrode the KVO methods on my AMAnnotation class. It turns out that each time I call setCoordinate: after the annotation has been added to the map, I see the following:

<AMAnnotation: 0x60800086eac0> _original_setCoordinate:
<AMAnnotation: 0x60800086eac0> addObserver:forKeyPath:options:context: <MKMapAnnotationManager: 0x60800038d270> coordinate

Now, I don't know what _original_setCoordinate: is, Google wasn't helpful. And it looks like the MKMapAnnotationManager re-adds itself as an observer but isn't removing itself.

Sometimes when the map is deallocated, I see that it removes itself multiple times. But other times not at all, which is when the warnings show up.

<AMAnnotation: 0x60800086eac0> removeObserver:forKeyPath: <MKMapAnnotationManager: 0x60800038d270> coordinate
<AMAnnotation: 0x60800086eac0> removeObserver:forKeyPath: <MKMapAnnotationManager: 0x60800038d270> coordinate
<AMAnnotation: 0x60800086eac0> removeObserver:forKeyPath: <MKMapAnnotationManager: 0x60800038d270> coordinate
<AMAnnotation: 0x60800086eac0> removeObserver:forKeyPath: <MKMapAnnotationManager: 0x60800038d270> coordinate
<AMAnnotation: 0x60800086eac0> dealloc

Anyone have an explanation for this? Thanks.

Upvotes: 0

Views: 254

Answers (1)

Brian Toth
Brian Toth

Reputation: 549

I hate when this happens, but it looks like I solved it. It seems that the MKMapAnnotationManager gets confused when updating an annotation with an invalid coordinate. (At least, that's what I've observed while debugging this problem.) If I check for invalid coordinates before updating the annotation and remove the annotation if it is invalid and re-add when valid, it seems to work and properly calls the add/remove observer methods as needed.

You can check for a valid coordinate with CLLocationCoordinate2DIsValid(). Also the constant kCLLocationCoordinate2DInvalid might come in handy.

Upvotes: 1

Related Questions