Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What causes this exception to be thrown "observer error"?

I only get this error if it is iOS 7 and if I include spcluster custom map (super pin map). Why does this error occur and how do I fix it?

 *** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <MKMapAnnotationManager 0xb355a00> for the key path "coordinate" from <Annotation 0x194c1470> because it is not registered as an observer.'
like image 370
user2997441 Avatar asked Nov 24 '13 16:11

user2997441


3 Answers

I had this exact same issue.

You can solve it by doing this.

  1. Create a subclass of MKAnnotation or add the following to your existing subclass.
  2. In it, add a variable (this is in Swift but you can interpret this for ObjC as well):
    var observers: NSMutableSet! = NSMutableSet()
  1. Then, add the following methods:
    override func addObserver(observer: NSObject, forKeyPath keyPath: String, options: NSKeyValueObservingOptions, context: UnsafeMutablePointer) {
        let observerId : String = "\(observer.hashValue)\(keyPath)"

        self.observers.addObject(observerId)
        super.addObserver(observer, forKeyPath: keyPath, options: options, context: context)
    }

    override func removeObserver(observer: NSObject, forKeyPath keyPath: String) {

        let observerId : String = "\(observer.hashValue)\(keyPath)"

        if (self.observers.containsObject(observerId)) {
            self.observers.removeObject(observerId)
            super.removeObserver(observer, forKeyPath: keyPath)
        }
    }
  1. Use this subclass with your MKMapView.

For debugging, if you add an "NSLog" statement inside of an else block in removeObserver() you can see that occasionally MKMapView (or it's MKAnnotationManager) will randomly decide to remove observation for an MKAnnotation that it's already asked for observation to removed from. This is, according to Apple's own KVO documentation, not to be done.

These overrides "fix" the problem as they keep track (on a per-annotation basis) which observations have already been registered for each annotation, thus allowing you to refuse to de-observe something that has already been de-observed (or never was observed in the first place).

It's kludgy, but they fixed my animation crash. And do so without much performance overhead.

like image 72
SimplePanda Avatar answered Oct 17 '22 00:10

SimplePanda


In my experience, a common cause of this is that coordinate was being observed through a multi-element key path and one of the intermediary keys was modified in a non-KVO-compliant manner. This leaves the internal KVO machinery observing one thing when it thinks it's observing a different thing. Some time later, when a part of the key path is changed in a KVO-compliant manner, this exception is raised.

like image 25
Ken Thomases Avatar answered Oct 17 '22 02:10

Ken Thomases


I've had a more generic issue with this observer error using only classic annotations on a MKMapView.

When trying to execute mMapView.removeAnnotations(mMapView.annotations), I randomly ran into this crash.

Just changing it to :

for annotation in mMapView.annotations {
    mMapView.deselectAnnotation(annotation as! MKAnnotation, animated: false)
    mMapView.removeAnnotation(annotation as! MKAnnotation)
}

solved my problem.

I can relate it to @Aurelien Porte 's comment.

like image 40
user2700551 Avatar answered Oct 17 '22 01:10

user2700551