设置地图视图中心坐标后,自定义注释视图将从其超级视图中删除

发布于 2024-11-26 22:04:53 字数 3203 浏览 3 评论 0原文

我正在开发一个位置感知应用程序,该应用程序使用 MKMapView 和作为 MKAnnotationView 子类实现的自定义标注气泡。昨天,当自定义注释视图未显示时,我遇到了一个微妙的错误。在对这个问题进行了一番研究后,我得出了以下结果:

  • 仅当我尝试在使用捏合手势缩放后立即显示自定义注释视图时,此问题才会显现出来。因此,例如,如果您捏住然后平移地图视图,一切都会正常。以编程方式更改地图缩放不会导致出现此问题
  • 在我的自定义注释视图类中的 didMoveToSuperview 中设置断点会显示以下回溯:

    #0 -[CalloutMapAnnotationView didMoveToSuperview] 
    #1 0x00186857 in -[UIView(层次结构)removeFromSuperview]()
    #2 0x00e14c70 in -[MKAnnotationContainerView _removeAnnotationView:updateCollections:] ()
    #3 0x00e196cb in -[MKAnnotationContainerView _removeAnnotationViews:] ()
    #4 0x00e19f51 in -[MKAnnotationContainerView _displayAnnotationsInMapRect:includePending:animated:removeOffscreenAnnotations:] ()
    #5 0x00e1aaa7 in -[MKAnnotationContainerView _refreshDisplayedAnnotations] ()
    #6 0x00dfc508 in -[MKMapView _didChangeRegionMidstream:centerPoint:] ()
    #7 0x00e0165c in -[MKMapView _goToCenterCoordinate:zoomLevel:animationType:] ()
    #8 0x00df34c3 in -[MKMapView goToCenterCooperative:zoomLevel:animationType:] ()
    #9 0x00e0086f in -[MKMapView setCenterCoordinate:animated:] ()
    #10 0x00036fc3 in -[CalloutMapAnnotationView adjustmentMapRegionIfNeeded] 
    #11 0x00037c63 在 -[CalloutMapAnnotationView didMoveToSuperview]
    #12 0x0017f750 in -[UIView(内部) _addSubview:positioned:relativeTo:] ()
    #13 0x0017dc00 in -[UIView(层次结构) insertSubview:atIndex:] ()
    #14 0x00e2049f in -[MKAnnotationContainerView _addViewForAnnotation:] ()
    #15 0x00e199a5 in -[MKAnnotationContainerView _addViewsForAnnotations:animated:] ()
    #16 0x00e19f0d in -[MKAnnotationContainerView _displayAnnotationsInMapRect:includePending:animated:removeOffscreenAnnotations:] ()
    #17 0x00e1a9e2 in -[MKAnnotationContainerView showAddedAnnotationsAnimated:] ()
    

这里,CalloutMapAnnotationView 是我的自定义注释视图类。如果注释太靠近地图边界,则 adjustMapRegionIfNeeded 方法会调整地图视图的中心坐标,从而导致从其超级视图中删除 CalloutMapAnnotationView 实例。为什么会发生这种情况以及解决方法可能是什么?

进一步的调查显示出更奇怪的行为。我在 adjustMapRegionIfNeeded 中添加了一堆调试 NSLogs 来打印每个注释的可见性,并得出以下结果:

正常情况(显示自定义注释):

Custom callout annotation location: (55.821350, 37.497490)
Parent annotation location: (55.821350, 37.497490)
Custom callout annotation visibility before adjustment: 1
Custom callout annotation visibility after adjustment: 1
Parent annotation visibility: 1

自定义注释不显示:

Custom callout annotation location: (55.821350, 37.497490)
Parent annotation location: (55.821350, 37.497490)
Custom callout annotation visibility before adjustment: 1
Custom callout annotation visibility after adjustment: 0
Parent annotation visibility: 1

尽管父注释和自定义标注注释具有相同的位置,但其中一个可见,而另一个不可见。我正在使用以下代码测试注释可见性:

[[self.mapView annotationsInMapRect:self.mapView.visibleMapRect] containsObject:self.annotation]

不仅如此,以下断言失败

MKMapRect visibleMapRect = self.mapView.visibleMapRect;
MKMapPoint annotationPoint = MKMapPointForCoordinate(self.annotation.coordinate);
NSAssert(MKMapRectContainsPoint(visibleMapRect, annotationPoint) == [[self.mapView annotationsInMapRect:visibleMapRect] containsObject:self.annotation], @"?!");

I'm working on a location-aware application that is using MKMapView with custom callout bubbles implemented as MKAnnotationView subclass. Yesterday I've encountered a subtle bug when custom annotation view is not being shown. After investigating this issue a bit, I've come up with following results:

  • this issue manifests itself only if I'm trying to show custom annotation view immediately after zooming with pinch gesture. So for example if you pinch and then pan the map view everything works fine. Programmatically changing map zoom doesn't cause this issue to appear either
  • setting breakpoint in didMoveToSuperview in my custom annotation view class reveals the following backtrace:

    #0  -[CalloutMapAnnotationView didMoveToSuperview] 
    #1  0x00186857 in -[UIView(Hierarchy) removeFromSuperview] ()
    #2  0x00e14c70 in -[MKAnnotationContainerView _removeAnnotationView:updateCollections:] ()
    #3  0x00e196cb in -[MKAnnotationContainerView _removeAnnotationViews:] ()
    #4  0x00e19f51 in -[MKAnnotationContainerView _displayAnnotationsInMapRect:includePending:animated:removeOffscreenAnnotations:] ()
    #5  0x00e1aaa7 in -[MKAnnotationContainerView _refreshDisplayedAnnotations] ()
    #6  0x00dfc508 in -[MKMapView _didChangeRegionMidstream:centerPoint:] ()
    #7  0x00e0165c in -[MKMapView _goToCenterCoordinate:zoomLevel:animationType:] ()
    #8  0x00df34c3 in -[MKMapView goToCenterCoordinate:zoomLevel:animationType:] ()
    #9  0x00e0086f in -[MKMapView setCenterCoordinate:animated:] ()
    #10 0x00036fc3 in -[CalloutMapAnnotationView adjustMapRegionIfNeeded] 
    #11 0x00037c63 in -[CalloutMapAnnotationView didMoveToSuperview]
    #12 0x0017f750 in -[UIView(Internal) _addSubview:positioned:relativeTo:] ()
    #13 0x0017dc00 in -[UIView(Hierarchy) insertSubview:atIndex:] ()
    #14 0x00e2049f in -[MKAnnotationContainerView _addViewForAnnotation:] ()
    #15 0x00e199a5 in -[MKAnnotationContainerView _addViewsForAnnotations:animated:] ()
    #16 0x00e19f0d in -[MKAnnotationContainerView _displayAnnotationsInMapRect:includePending:animated:removeOffscreenAnnotations:] ()
    #17 0x00e1a9e2 in -[MKAnnotationContainerView showAddedAnnotationsAnimated:] ()
    

Here, CalloutMapAnnotationView is my custom annotation view class. adjustMapRegionIfNeeded method adjusts map view's center coordinate if annotation is too close to map borders which in turn causes removal of CalloutMapAnnotationView instance from its superview. Why this is happening and what a workaround may be?

Further investigation showed even more strange behavior. I added a bunch of debug NSLogs in adjustMapRegionIfNeeded to print each annotation visibility and came up up with following result:

Normal case (custom annotation is displayed):

Custom callout annotation location: (55.821350, 37.497490)
Parent annotation location: (55.821350, 37.497490)
Custom callout annotation visibility before adjustment: 1
Custom callout annotation visibility after adjustment: 1
Parent annotation visibility: 1

Custom annotation is not displayed:

Custom callout annotation location: (55.821350, 37.497490)
Parent annotation location: (55.821350, 37.497490)
Custom callout annotation visibility before adjustment: 1
Custom callout annotation visibility after adjustment: 0
Parent annotation visibility: 1

Despite parent annotation and custom callout annotation having the same location, one of them is visible while the other is not. I'm testing annotation visibility with the following code:

[[self.mapView annotationsInMapRect:self.mapView.visibleMapRect] containsObject:self.annotation]

More than that, the following assertion fails:

MKMapRect visibleMapRect = self.mapView.visibleMapRect;
MKMapPoint annotationPoint = MKMapPointForCoordinate(self.annotation.coordinate);
NSAssert(MKMapRectContainsPoint(visibleMapRect, annotationPoint) == [[self.mapView annotationsInMapRect:visibleMapRect] containsObject:self.annotation], @"?!");

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青丝拂面 2024-12-03 22:04:53

我遇到了同样的问题(并且很可能使用了与您相同的教程)。

我将一些 NSLogs 放入 CalloutAnnotationViewdidMoveToSuperView 中,发现添加 CalloutAnnotationView 之后,其超级视图,MKAnnotationContainerView 的一个实例正在发布。这可能意味着 MKMapView 在放大或缩小时会在内部重新创建其 MKAnnotationContainerView

我所做的就是在添加它之后做了一些检查:

[self.mapView addAnnotation: m_calloutAnnotation];
[self performSelector: @selector(checkCalloutAnnotationVisibility)
           withObject: nil
           afterDelay: 0.15];
...

- (void) checkCalloutAnnotationVisibility
{
  if (!m_calloutAnnotationView.window)
  {
    [self.mapView removeAnnotation: m_calloutAnnotation];
    [self.mapView addAnnotation: m_calloutAnnotation];

    [self performSelector: @selector(checkCalloutAnnotationVisibility)
               withObject: nil
               afterDelay: 0.1];
  }
}

...

- (void)          mapView: (MKMapView *)        mapView
didDeselectAnnotationView: (MKAnnotationView *) view
{
  [NSObject cancelPreviousPerformRequestsWithTarget: self
                                           selector:
                                     @selector(checkCalloutAnnotationVisibility)
                                             object: nil];
  ...
}

是的,这非常hacky。如果您找到更好的解决方案,请发帖。 :)

I've come across the same problem (and most probably used the same tutorial that you did).

I've put some NSLogs into the CalloutAnnotationView's didMoveToSuperView and found that after adding the CalloutAnnotationView, its superview, an instance of MKAnnotationContainerView, is being released. This could mean that the MKMapView internally recreates its MKAnnotationContainerView when zooming in or out.

What I did was to do some checking a little bit after adding it:

[self.mapView addAnnotation: m_calloutAnnotation];
[self performSelector: @selector(checkCalloutAnnotationVisibility)
           withObject: nil
           afterDelay: 0.15];
...

- (void) checkCalloutAnnotationVisibility
{
  if (!m_calloutAnnotationView.window)
  {
    [self.mapView removeAnnotation: m_calloutAnnotation];
    [self.mapView addAnnotation: m_calloutAnnotation];

    [self performSelector: @selector(checkCalloutAnnotationVisibility)
               withObject: nil
               afterDelay: 0.1];
  }
}

...

- (void)          mapView: (MKMapView *)        mapView
didDeselectAnnotationView: (MKAnnotationView *) view
{
  [NSObject cancelPreviousPerformRequestsWithTarget: self
                                           selector:
                                     @selector(checkCalloutAnnotationVisibility)
                                             object: nil];
  ...
}

It's pretty hacky, yes. If you find a better solution, please do post. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文