如何解决导致重复标注的 MapKit 错误?
Posted
技术标签:
【中文标题】如何解决导致重复标注的 MapKit 错误?【英文标题】:How can I work around this MapKit bug that causes duplicate callouts? 【发布时间】:2015-01-16 23:06:47 【问题描述】:有一个bug in MapKit that can cause duplicate callout views on an annotation。如果时机恰到好处,注释视图可以在它被选中时被重新使用,显然就在标注视图被实际添加到它之前。结果,旧的标注视图被卡在那里,而新的标注将出现在它的顶部或旁边。这是在 OS X 应用程序中的样子:
这张地图上只有一个注释。如果您单击地图上的其他位置以取消选择注记,则只有一个标注会消失。在某些情况下,您可能有两个信息完全不同的标注,这会让使用您的应用的人感到非常困惑。
这是我整理的一个示例 OS X 项目的大部分内容,用于说明此错误:
@import MapKit;
#import "AppDelegate.h"
#import "JUNMapAnnotation.h"
@interface AppDelegate () <MKMapViewDelegate>
@property (weak) IBOutlet NSWindow *window;
@property (weak) IBOutlet MKMapView *mapView;
@property BOOL firstPin;
- (void)placeAndSelectPin;
- (JUNMapAnnotation *)placePin;
- (void)clearPins;
@end
@implementation AppDelegate
- (IBAction)dropSomePins:(id)sender
self.firstPin = YES;
[self placeAndSelectPin];
[self performSelector:@selector(placeAndSelectPin) withObject:nil afterDelay:0.0001];
#pragma mark - Private methods
- (void)placeAndSelectPin
[self clearPins];
JUNMapAnnotation *annotation = [self placePin];
[self.mapView deselectAnnotation:annotation animated:NO];
[self.mapView selectAnnotation:annotation animated:YES];
- (JUNMapAnnotation *)placePin
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(50.0,50.0);
JUNMapAnnotation *annotation = [[JUNMapAnnotation alloc] initWithCoordinate:coord];
annotation.title = @"Annotation";
annotation.subtitle = (self.firstPin) ? @"This is an annotation with a longer subtitle" : @"This is an annotation";
[self.mapView addAnnotation:annotation];
self.firstPin = NO;
return annotation;
- (void)clearPins
[self.mapView removeAnnotations:self.mapView.annotations];
#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
if ([annotation isKindOfClass:[JUNMapAnnotation class]])
static NSString *identifier = @"annotationView";
MKPinAnnotationView *view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (view == nil)
view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
view.canShowCallout = YES;
NSLog(@"new annotation view");
else
view.annotation = annotation;
return view;
return nil;
@end
ios 中似乎也存在同样的错误,尽管我在那里重新创建它时遇到了困难。
虽然我正在等待 Apple 解决此问题,但我想尽可能地解决它。到目前为止,我提出了一些可能性:
-
不要重复使用注释视图。据我所知,这似乎是完全避免该错误的唯一方法,但似乎效率很低。
当注释视图在
mapView:viewForAnnotation:
中重复使用时,删除其所有子视图。目前,标注似乎是唯一的子视图,尽管它似乎不是一个特别安全的黑客。它也只是一种工作方式——它不会阻止重复标注的出现,它只是防止它们永远存在。 (当这个错误第一次发生时,实际上还没有任何子视图。)
结合这两者:如果dequeueReusableAnnotationViewWithIdentifier:
返回一个包含任何子视图的视图,忽略它并创建一个新视图。这似乎比 2 安全得多,而且效率也不像 1 那样低。但与 2 一样,它并不是一个完整的解决方法。
我还尝试在我能想到的每个地方添加deselectAnnotation:animated:
,但我找不到任何可行的方法。我假设一旦注释视图被重新使用,MapView 就会失去对第一个标注的跟踪,因此它的任何常规方法都不会摆脱它。
【问题讨论】:
【参考方案1】:这有点超出了左侧字段,但是..
尝试使用 2 个不同的重用标识符注册相同的单元类。在viewForAnnotation:
中,在出列单元格时交替使用每个标识符。这应该可以防止连续两次从同一个队列中抓取。
【讨论】:
有趣的是,这在我的 OS X 测试应用程序中有效,以前我每次都能重新创建错误。但后来我在 iOS 上尝试了同样的事情,我能够立即重新创建错误。真可惜。好主意!viewForAnnotation:
可能在不同的线程上被调用。您可能想尝试将 @synchronized(self)
包裹在方法中的所有内容上。以上是关于如何解决导致重复标注的 MapKit 错误?的主要内容,如果未能解决你的问题,请参考以下文章