是什么原因导致此异常被抛出“观察者错误”?

时间:2013-11-24 16:26:06

标签: ios iphone objective-c

如果它是iOS 7并且我包含spcluster自定义地图(超级引脚映射),我只会收到此错误。为什么会出现此错误以及如何解决?

 *** 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.'

7 个答案:

答案 0 :(得分:4)

我有同样的问题。

你可以通过这样做来解决它。

  1. 创建MKAnnotation的子类或将以下内容添加到现有的子类中。
  2. 在其中,添加一个变量(这是在Swift中,但你也可以为ObjC解释这个):
  3.     var observers: NSMutableSet! = NSMutableSet()
    
    1. 然后,添加以下方法:
    2.     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. 将此子类与MKMapView一起使用。
      2. 对于调试,如果在removeObserver()中的 else 块内添加“NSLog”语句,您可以看到偶尔MKMapView(或它的MKAnnotationManager)将随机决定删除MKAnnotation的观察它已被要求进行观察以从中删除。根据Apple自己的KVO文档,这是不可行的。

        这些覆盖“修复”问题,因为它们跟踪(在每个注释的基础上)已经为每个注释记录了哪些观察结果,因此允许您拒绝去除已观察到的东西(或者从未在第一时间观察过。)

        这很糟糕,但他们修复了我的动画崩溃。并且这样做没有太多的性能开销。

答案 1 :(得分:2)

根据我的经验,其常见原因是通过多元素密钥路径观察到coordinate,并且以非KVO兼容方式修改了其中一个中间密钥。这使得内部KVO机器在认为它正在观察不同的东西时会观察到一件事。一段时间之后,当以符合KVO的方式更改密钥路径的一部分时,会引发此异常。

答案 2 :(得分:1)

在MKMapView上只使用经典注释时,我遇到了一个更普遍的问题。

尝试执行mMapView.removeAnnotations(mMapView.annotations)时,我随机遇到了这次崩溃。

只需将其更改为:

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

解决了我的问题。

我可以将它与@Aurelien Porte的评论联系起来。

答案 3 :(得分:0)

您(或开发该组件的任何人)正在尝试通过调用MKMapAnnotationManager删除Annotation coordinate(关键路径removeObserver:forKeyPath:context:)的观察者。但是MKMapAnnotationManager未注册为观察者,因此崩溃。

此修复是为了确保对addObserver / removeObserver的呼叫始终保持平衡。

没有进一步的细节,可以这么说。

作为额外参考,以下是此nice blog article about KVO的相关引用:

  

或许对KVO最深刻的烦恼是,如果你在对象未注册为观察者的情况下调用 - removeObserver:forKeyPath:context:(无论是因为它尚未注册或首先未注册),抛出一个例外。踢球者是没有内置的方法来检查对象是否已注册!

答案 4 :(得分:0)

当使用apple文档提供的一些代码来集群化MKMapView注释时,我遇到了这样的错误。它可以在示例项目PhotoMap中找到。

我的问题是在动画完成之前已取消分配父视图和MKMapView。动画正在为注释坐标设置动画(正在移动地图上的注释)

for (MyMKAnnotation *annotation in filteredAnnotationsInBucket) {
    // give all the other annotations a reference to the one which is representing them
    annotation.clusterAnnotation = annotationForGrid;
    annotation.containedAnnotations = nil;

    // remove annotations which we've decided to cluster
    if ([visibleAnnotationsInBucket containsObject:annotation]) {
        CLLocationCoordinate2D actualCoordinate = annotation.coordinate;

        // This is the flag that I added to disable/enable animation
        if (animateMarkerClustering) {

            // This animation is not finished properly before the annotationViews
            // animation gets finished
            [UIView animateWithDuration:0.3 animations:^{
                annotation.coordinate = annotation.clusterAnnotation.coordinate;
            } completion:^(BOOL finished) {
                annotation.coordinate = actualCoordinate;
                [_mapView removeAnnotation:annotation];
            }];

        } else {
            annotation.coordinate = actualCoordinate;
            [_mapView removeAnnotation:annotation];
        }
    }
}

我尝试删除[self.view removeAllAnimations]

上的动画

if (_mapView.annotations.count > 0){
    NSArray *annotations =_mapView.annotations;

    for(int i=0;i<annotations.count;i++){
        id <MKAnnotation> annotation = annotations[i];

        [[_mapView viewForAnnotation:annotation].layer removeAllAnimations];
        [_mapView removeAnnotation:annotation];
    }

    //[_mapView removeAnnotations:_mapView.annotations];
}

我什么都没有。

暂时我设置animateMarkerClustering=NO来禁用注释动画,这是有效的。没错。

答案 5 :(得分:0)

好的,我还没有足够的声誉来评论这个问题,但我用上面的答案解决了我完全相同的情况:https://stackoverflow.com/a/31231307/2248650

也像slava我使用Apple的示例项目PhotoMap作为我实现的基础,但我也将它移植到Swift。我还有子类化MKAnnotation并启用其样本中的坐标动画,我必须设置动态关键字来协调:

dynamic var coordinate: CLLocationCoordinate2D

现在,就像呈现一样,当我在删除注释之前取消选择注释

for annotation in allAnnotationsMapView.annotations {
    allAnnotationsMapView.deselectAnnotation(annotation, animated: false)
    allAnnotationsMapView.removeAnnotation(annotation)
}

我不再遇到异常了。

答案 6 :(得分:0)

XKAnnotation的子类

更改

const isFile = input => 'File' in window && input instanceof File;
const isBlob = input => 'Blob' in window && input instanceof Blob;

const a = new File([1,2,3], "foo.txt", {type: "text/plain"});
...

console.log(isFile(a)) // true
...

class Fibonacci:

    def __init__(self, max = 0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max: # if n is less that 0
            def FIB(number):
                if number == 1 or number == 2:
                    return 1
                else:
                    return FIB(number - 1) + FIB(number - 2)
            self.n += 1
        else:
            raise StopIteration