当用户触摸标注时出现未识别选择器崩溃

10

我有一个用于显示地图和自定义标注的应用程序。当用户触摸标注时,我的应用程序会崩溃。这只会在 iOS 7 中发生。在 iOS 6 和 iOS 5 中运行良好。

以下是控制台中显示的崩溃报告:

ERROR: Trying to select an annotation which has not been added
-[__NSSetM coordinate]: unrecognized selector sent to instance 0x18c9d580
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSetM coordinate]: unrecognized selector sent to instance 0x18c9d580'
*** First throw call stack:
(
    0   CoreFoundation                      0x020415e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x016918b6 objc_exception_throw + 44
    2   CoreFoundation                      0x020de903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
    3   CoreFoundation                      0x0203190b ___forwarding___ + 1019
    4   CoreFoundation                      0x0206e46e __forwarding_prep_1___ + 14
    5   MapKit                              0x000de10c _Z21_insertionNodeForItemP11objc_objectP14MKQuadTrieNode + 50
    6   MapKit                              0x000de428 _Z9_containsP11objc_objectP14MKQuadTrieNode + 27
    7   MapKit                              0x000de8ed -[MKQuadTrie contains:] + 39
    8   MapKit                              0x000d4918 -[MKAnnotationManager selectAnnotation:animated:avoid:] + 116
    9   MapKit                              0x00090789 -[MKMapView handleTap:] + 541
    10  UIKit                               0x0056ae8c _UIGestureRecognizerSendActions + 230
    11  UIKit                               0x00569b00 -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 383
    12  UIKit                               0x0056b56d -[UIGestureRecognizer _delayedUpdateGesture] + 60
    13  UIKit                               0x0056eacd ___UIGestureRecognizerUpdate_block_invoke + 57
    14  UIKit                               0x0056ea4e _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 317
    15  UIKit                               0x00565148 _UIGestureRecognizerUpdate + 199
    16  CoreFoundation                      0x020094ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
    17  CoreFoundation                      0x0200941f __CFRunLoopDoObservers + 399
    18  CoreFoundation                      0x01fe7344 __CFRunLoopRun + 1076
    19  CoreFoundation                      0x01fe6ac3 CFRunLoopRunSpecific + 467
    20  CoreFoundation                      0x01fe68db CFRunLoopRunInMode + 123
    21  GraphicsServices                    0x01f6c9e2 GSEventRunModal + 192
    22  GraphicsServices                    0x01f6c809 GSEventRun + 104
    23  UIKit                               0x001f2d3b UIApplicationMain + 1225
    24  CustomMKAnnotationView              0x0000285a main + 170
    25  CustomMKAnnotationView              0x000027a5 start + 53
)
libc++abi.dylib: terminating with uncaught exception of type NSException

我已按以下方式创建了代码:

-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
    if ([view.annotation isKindOfClass:[BasicMapAnnotation class]])
        {
        if (_calloutAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&&
            _calloutAnnotation.coordinate.longitude == view.annotation.coordinate.longitude)
        {
            return;
        }
        if (_calloutAnnotation)
        {
            [mapView removeAnnotation:_calloutAnnotation];
            _calloutAnnotation = nil;
        }
        _calloutAnnotation = [[[CalloutMapAnnotation alloc] 
                               initWithLatitude:view.annotation.coordinate.latitude
                              andLongitude:view.annotation.coordinate.longitude]autorelease];
        [mapView addAnnotation:_calloutAnnotation];

        [mapView setCenterCoordinate:_calloutAnnotation.coordinate animated:YES];
    }else
    {
        if([delegate respondsToSelector:@selector(customMKMapViewDidSelectedWithInfo:)])
        {
            [delegate customMKMapViewDidSelectedWithInfo:@"Annotation clicked"];
        }
    }
}

-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view 
    {
    if (_calloutAnnotation&& ![view isKindOfClass:[CallOutAnnotationVifew class]])
    {
        if (_calloutAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&&
            _calloutAnnotation.coordinate.longitude == view.annotation.coordinate.longitude)
        {
            [mapView removeAnnotation:_calloutAnnotation];
            _calloutAnnotation = nil;
        }
    }
}

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    if ([annotation isKindOfClass:[CalloutMapAnnotation class]])
    {

        CallOutAnnotationVifew *annotationView = (CallOutAnnotationVifew *)[mapView     dequeueReusableAnnotationViewWithIdentifier:@"CalloutView"];
        if (!annotationView)
        {
            annotationView = [[[CallOutAnnotationVifew alloc] initWithAnnotation:annotation reuseIdentifier:@"CalloutView"] autorelease];
            JingDianMapCell  *cell = [[[NSBundle mainBundle] loadNibNamed:@"JingDianMapCell" owner:self options:nil] objectAtIndex:0];
            cell.titleLable.text = @"Testing";
            [annotationView.contentView addSubview:cell];

        }
        return annotationView;
    }else if ([annotation isKindOfClass:[BasicMapAnnotation class]])
    {

         MKAnnotationView *annotationView =[self.mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomAnnotation"];
        if (!annotationView)
        {
            annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation 
                                                           reuseIdentifier:@"CustomAnnotation"] autorelease];
            annotationView.canShowCallout = NO;
            annotationView.image = [UIImage imageNamed:@"pin.png"];
        }

        return annotationView;
    }
    return nil;
}
在didSelectAnnotationView和didDeselectAnnotationView方法中,我添加了新的注释视图并移除旧的注释视图。注释视图是自定义类。_calloutAnnotation是CalloutMapAnnotation对象,它是用于添加注释的NSObject类。

在didSelectAnnotationView和didDeselectAnnotationView方法中,我添加了新的注释视图并移除旧的注释视图。注释视图是自定义类。_calloutAnnotation是CalloutMapAnnotation对象,它是用于添加注释的NSObject类。


_calloutAnnotation 用于什么?你的应用程序中是否调用了 selectAnnotation?简单来说,didSelectAnnotationViewdidDeselectAnnotationView 中的代码试图做什么(如果答案很长,请在问题中添加解释)。 - user467105
应用程序是否在任何地方调用了selectAnnotation?确保在添加注释后调用selectAnnotation。看起来_calloutAnnotation或其他注释变量在包含无效引用(不是id<MKAnnotation>)时被引用。 - user467105
3个回答

1

Marcin部分正确。然而,最终的线索在于ERROR: Trying to select an annotation which has not been added。 这里发生的情况是用户点击了一个“标注气泡”,实际上是一个注释视图。作为其中的一部分,MapView首先取消选择当前选定的注释,然后选择用户点击的注释。 但是,由于您已经在取消选择步骤中从地图中删除了要选择的注释,因此没有任何东西可供选择。因此,在调试器中出现“ERROR…”消息。

-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view 
{
  if (_calloutAnnotation&& ![view isKindOfClass:[CallOutAnnotationVifew class]])
  {
    if (_calloutAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&&
        _calloutAnnotation.coordinate.longitude == view.annotation.coordinate.longitude)
    {
        CalloutMapAnnotation *oldAnnotation = self.calloutAnnotation; //saving it to be removed from the map later
        self.calloutAnnotation = nil; //setting to nil to know that we aren't showing a callout anymore
        dispatch_async(dispatch_get_main_queue(), ^{
            [mapView removeAnnotation:oldAnnotation]; //removing the annotation a bit later
        });
    }
  }
}

是的,你说得对。这是更清洁和更安全的处理方式。我的代码存在影响错误,可能会导致选择多个注释。 - Marcin Małysz

1

_calloutAnnotation 中不包含注释视图。我认为你在某个地方有这样的代码 @property (weak, nonatomic) MKAnnotation * calloutAnnotation;weak 改为 strong 应该会有帮助。


0

你的问题在这里:

-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view 
    {
    if (_calloutAnnotation&& ![view isKindOfClass:[CallOutAnnotationVifew class]])
    {
        if (_calloutAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&&
            _calloutAnnotation.coordinate.longitude == view.annotation.coordinate.longitude)
        {
            [mapView removeAnnotation:_calloutAnnotation];
//EDIT: This code is broken don't use it :)
            //in iOS7.0 responder chain is changed a bit and you can't call this directly give it some time or remove this line and your crash will be gone ;)
//            double delayInSeconds = 0.5;
//        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
//        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//            _calloutAnnotation = nil;
//        });
        }
    }
}

为避免可能的竞争条件,我建议不要在超时后进行调度。以下代码同样有效:dispatch_async(dispatch_get_main_queue(), ^{self.calloutAnnotation = nil;}); 或者 [self performSelectorOnMainThread:@selector(setCalloutAnnotation:) withObject:nil waitUntilDone:NO]; 在任何情况下,当主线程空闲时,操作将在主线程上执行。此外,这仍然只是一个解决方法,并不能清除控制台中的“ERROR…”消息。 - user3099609

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接