当用户触摸注释时,无法识别的选择器崩溃
Posted
技术标签:
【中文标题】当用户触摸注释时,无法识别的选择器崩溃【英文标题】:Crash with unrecognized selector when user touches annotation 【发布时间】:2013-11-29 00:33:56 【问题描述】:我有一个用于显示地图和自定义注释的应用程序。当用户触摸注释时,我的应用程序崩溃。它仅发生在 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 类。
【问题讨论】:
_calloutAnnotation
是做什么用的?你在你的应用程序中调用selectAnnotation
吗?简而言之,didSelectAnnotationView 和 didDeselectAnnotationView 中的代码是什么(如果答案很长,请在问题中添加解释)。
应用程序是否在任何地方调用 selectAnnotation?确保在添加注释 之后调用 selectAnnotation。当 _calloutAnnotation 或其他注释变量包含无效引用(不是 id_calloutAnnotation
不包含注释视图。我认为你有这样的代码 @prorerty (weak, nonatomic) MKAnnotation * calloutAnnotation;
将 weak
更改为 strong
应该会有所帮助。
【讨论】:
【参考方案2】:Marcin 部分正确。然而最终的线索在于ERROR: Trying to select an annotation which has not been added
这里发生的是用户点击一个“标注气泡”,它实际上是一个注释视图。作为其中的一部分,MapView 首先取消选择当前选定的注释,然后选择用户点击的注释。
但是,由于您已经在取消选择步骤中从地图中删除了要选择的注释,因此没有任何内容可供选择。因此调试器中的“错误...”消息。
-(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
);
【讨论】:
是的,你是对的。这是处理这个问题的更清洁和更安全的方法。我的代码有可能以多个选定的注释结尾的影响错误。【参考方案3】:你的问题在这里:
-(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];
在任何一种情况下,只要主线程释放,就会在主线程上执行操作。此外,这仍然只是一种解决方法,不会清除控制台“错误...”消息。以上是关于当用户触摸注释时,无法识别的选择器崩溃的主要内容,如果未能解决你的问题,请参考以下文章
从另一个类触摸时的 Swift 按钮操作选择器:无法识别的选择器发送到实例
越狱设备 [UIDeviceRGBColor superview] 上 loadNibNamed 时可能崩溃:无法识别的选择器