Crash with unrecognized selector when user touches annotation
Asked Answered
D

3

10

I have an app for displaying map and custom annotation. My application crashes when the user touches on the annotation. It happens in iOS 7 only. It's working fine with iOS 6 and iOS 5.

Following is the crash report which is displayed in the console:

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

And I have created code in following manner:

-(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;
}

In didSelectAnnotationView and didDeselectAnnotationView I am add the new annotation view and remove the old annotation view. Annotation view is custom class. And _calloutAnnotation is a object of CalloutMapAnnotation which is NSObject class for add annotation.

Dave answered 15/11, 2013 at 15:5 Comment(2)
What is _calloutAnnotation used for? Are you calling selectAnnotation in your app? In plain English, what is the code in didSelectAnnotationView and didDeselectAnnotationView trying to do (add explanation to the question if the answer is long).Querida
Does the app call selectAnnotation anywhere? Make sure selectAnnotation is called after the annotation is added. It looks like _calloutAnnotation or some other annotation variable is being referenced when it contains an invalid reference (not an id<MKAnnotation>).Querida
W
1

_calloutAnnotation does not contain annotation view. I think that you have somewhere code like this @prorerty (weak, nonatomic) MKAnnotation * calloutAnnotation; changing weak to strong should help.

Written answered 15/11, 2013 at 16:47 Comment(0)
A
1

Marcin is partially right. However the ultimate clue lies in ERROR: Trying to select an annotation which has not been added What's happening here is that the user taps on a "callout bubble" which is actually an annotation view. As part of that, the MapView first deselects the currently selected annotation and then selects the annotation that the user tapped on. However, since you've already removed the annotation-to-be-selected from the map on the deselection step, there's nothing to be selected. Hence the "ERROR..." message in the debugger.

-(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
        });
    }
  }
}
Acceleration answered 19/2, 2014 at 18:4 Comment(1)
Yes, you are right. This is more cleaner and safer way to deal with this. My code have impact bug that may end with multiple selected Annotations.Regime
R
0

Your problem is here:

-(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;
//        });
        }
    }
}
Ragland answered 18/2, 2014 at 11:56 Comment(1)
To avoid possible race conditions I would suggest against dispatching after a timeout. The following should work just as well: dispatch_async(dispatch_get_main_queue(), ^{self.calloutAnnotation = nil;}); or [self performSelectorOnMainThread:@selector(setCalloutAnnotation:) withObject:nil waitUntilDone:NO]; in either case the action will be done on the main thread whenever it frees up. Also, this is still just a workaround and doesn't clear the console "ERROR..." message.Acceleration

© 2022 - 2024 — McMap. All rights reserved.