3

MKAnnotationView サブクラスとして実装されたカスタム コールアウト バブルで MKMapView を使用している位置認識アプリケーションに取り組んでいます。昨日、カスタム注釈ビューが表示されていないときに微妙なバグに遭遇しました。この問題を少し調べたところ、次の結果が得られました。

  • この問題は、ピンチ ジェスチャでズームした直後にカスタム注釈ビューを表示しようとした場合にのみ現れます。たとえば、マップ ビューをピンチしてからパンすると、すべて正常に動作します。プログラムでマップのズームを変更しても、この問題は発生しません
  • カスタム アノテーション ビュー クラスの didMoveToSuperview にブレークポイントを設定すると、次のバックトレースが表示されます。

    #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:] ()
    

ここで、CalloutMapAnnotationView はカスタム アノテーション ビュー クラスです。adjustMapRegionIfNeededメソッドは、注釈がマップの境界線に近すぎる場合にマップ ビューの中心座標を調整します。これにより、そのスーパービューから CalloutMapAnnotationView インスタンスが削除されます。これが発生する理由と回避策を教えてください。

さらに調査すると、さらに奇妙な動作が示されました。各注釈の可視性を出力するために一連のデバッグ NSLog を追加しadjustMapRegionIfNeededたところ、次の結果が得られました。

通常の場合 (カスタム アノテーションが表示されます):

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], @"?!");
4

1 に答える 1

1

私は同じ問題に遭遇しました (そして、おそらくあなたが行ったのと同じチュートリアルを使用しました)。

CalloutAnnotationViewいくつかのNSLog を に入れましたが、 を追加した、そのスーパービューである のインスタンスが解放されていることdidMoveToSuperViewがわかりました。これは、ズームインまたはズームアウト時にが内部的に再作成することを意味する場合があります。CalloutAnnotationViewMKAnnotationContainerViewMKMapViewMKAnnotationContainerView

私がしたことは、追加した後に少しチェックすることでした:

[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];
  ...
}

はい、かなりハッキーです。より良い解決策を見つけた場合は、投稿してください。:)

于 2011-08-22T07:10:42.647 に答える