1

MKMapView でオーバーレイを実行したいと考えています。そこで、カスタム オブジェクトを作成しました。

@interface Spot : NSObject

@property int spot_id;
@property CLLocationCoordinate2D coordinate;
@property float radius;
@property NSObject<MKOverlay> * overlay;

- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(float)radius;

@end

スポットを常に更新して電話に配信するバックエンドがあります。だから私はしなければなりません:

  • 現在レンダリングされているスポットがまだ有効であるかどうかを確認します。
  • はいの場合、半径を移動または変更しましたか? もしそうなら、それらを更新します (移動? / 削除 + 再描画?!)
  • それらがもう存在しない場合は削除します。

オーバーレイを追跡するより良い方法はありますか? 各スポットに参照を付けたままにしNSObject<MKoverlay> * 、常に再割り当てするのは少し奇妙に感じます。

4

1 に答える 1

2

ここには3つの質問があるようです:

  1. サーバー内のスポットの変化を検出する方法は?

    これを行う醜い方法は、スポットを反復処理して、coordinateand/orradiusが変更されたかどうかを確認することです。もう少し良い方法は、サーバーにタイムスタンプまたはその他の識別子を作成、変更、および削除させて、クライアントが最後の更新以降のすべての作成、変更、および/または削除を取得できるようにすることです。これを何らかの形式のプッシュ通知と組み合わせて、クライアントにもこれらの変更が積極的に通知されるようにするのが最善です。

    この質問は、抽象的に答えるのが難しいです。これは、サーバーの機能とデータベースの性質 (「スポット」の数、変更頻度など) に大きく依存します。これは、クライアント サーバー アーキテクチャだけでなく、クライアントの実装にも影響します。

  2. スポットが変更されたときにマップを更新する方法は?

    これははるかに簡単な質問です。挿入と削除は簡単です。あなたはそうするだけですaddOverlay:(または、iOS 7では、addOverlay:level:そしてremoveOverlay:.アップデートの場合、それはエレガントではありませんが、古いオーバーレイを削除して再度追加するのが最も簡単な方法だと思いviewForOverlayます。ユーザーインターフェイスを処理します.

  3. Spotクラスの正しい構造は何ですか?

    coordinate考えてみると、あなたとradiusプロパティを持ち、オブジェクトも持つのは重複しているように見えますid<MKOverlay> overlay(おそらくMKCircle同じ2つのプロパティを持つ ため)。オーバーレイがMKCircleオブジェクトになる場合は、Spotクラス自体を準拠させる方が簡単な場合がありMKOverlayます。

    @interface Spot : NSObject <MKOverlay>
    
    @property (nonatomic) int spot_id;
    @property (nonatomic) CLLocationCoordinate2D coordinate;
    @property (nonatomic) CLLocationDistance radius;
    @property (nonatomic, readonly) MKMapRect boundingMapRect;
    
    - (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
    
    @end
    

    boundingMapRectあとは、 andを実装するだけですintersectsMapRect

    - (MKMapRect) boundingMapRect
    {
        MKMapPoint point = MKMapPointForCoordinate(self.coordinate);
        CLLocationDistance distance = self.radius * MKMetersPerMapPointAtLatitude(self.coordinate.latitude);
        MKMapRect rect = MKMapRectMake(point.x, point.y, distance * 2.0, distance * 2.0);
        rect = MKMapRectOffset(rect, -distance, -distance);
    
        return rect;
    }
    
    - (BOOL)intersectsMapRect:(MKMapRect)mapRect
    {
        return MKMapRectIntersectsRect(mapRect, [self boundingMapRect]);
    }
    

    その論理を再確認したいかもしれませんがboundingMapRect、それは正しいと思います。

    Spot次に、オブジェクトをオーバーレイ自体として追加および削除できます。そして、あなたがする必要があるのはviewForOverlay、あなたの に a を実装することだけですMKMapViewDelegate。たとえば、7 より前の iOS バージョンでは、次のようになります。

    - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
    {
        if ([overlay isKindOfClass:[Spot class]])
        {
            Spot *spot       = (id)overlay;
            MKCircle *circle = [MKCircle circleWithCenterCoordinate:spot.coordinate
                                                             radius:spot.radius];
    
            MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:circle];
            overlayView.fillColor     = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            overlayView.strokeColor   = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            overlayView.lineWidth     = 3.0;
            return overlayView;
        }
    
        return nil;
    }
    

    iOS 7 では、次のようになります。

    - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
    {
        if ([overlay isKindOfClass:[Spot class]])
        {
            Spot *spot       = (id)overlay;
            MKCircle *circle = [MKCircle circleWithCenterCoordinate:spot.coordinate
                                                             radius:spot.radius];
    
            MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:circle];
            renderer.fillColor         = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            renderer.strokeColor       = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            renderer.lineWidth         = 3;
    
            return renderer;
        }
    
        return nil;
    }
    

    別のアプローチは、次のように定義することSpotです。

    @interface Spot : NSObject <MKOverlay>
    
    @property (nonatomic) int spot_id;
    @property (nonatomic, strong) MKCircle *overlay;
    
    - (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
    

    次に、から適切な値を定義boundingMapRectしてcoordinate返すことができMKCircleます (独自に記述する必要がなくなります)。

    - (MKMapRect)boundingMapRect
    {
        return [self.circle boundingMapRect];
    }
    
    - (CLLocationCoordinate2D)coordinate
    {
        return [self.circle coordinate];
    }
    

    明らかに、initメソッドは次のように変更されます。

    - (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
    {
        self = [super init];
        if (self) {
            _spot_id = spot_id;
            _circle = [MKCircle circleWithCenterCoordinate:coordinate radius:radius];
        }
        return self;
    }
    

    viewForOverlayの(7.0 より前の iOS バージョン) と同様にMKMapViewDelegate:

    - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
    {
        if ([overlay isKindOfClass:[SpotCircle class]])
        {
            SpotCircle *spot = (id)overlay;
    
            MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:spot.circle];
            overlayView.fillColor     = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            overlayView.strokeColor   = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            overlayView.lineWidth     = 3.0;
    
            return overlayView;
        }
    
        return nil;
    }
    

    iOS 7 では、次のようになります。

    - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
    {
        if ([overlay isKindOfClass:[SpotCircle class]])
        {
            SpotCircle *spot = (id)overlay;
    
            MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:spot.circle];
            renderer.fillColor         = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            renderer.strokeColor       = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            renderer.lineWidth         = 3;
    
            return renderer;
        }
    
        return nil;
    }
    

それが役立つことを願っています。

于 2013-05-12T04:23:45.593 に答える