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

有一个后端,不断更新 Spot 并将它们传送到手机。所以我必须要:

  • 检查当前渲染的点是否仍然有效并且存在
  • 如果是,他们是否移动或改变了半径?如果是这样,更新它们(移动?/删除+重绘?!)
  • 如果它们不再存在,请删除。

有没有更好的方法来跟踪覆盖?为每个位置保留一个NSObject<MKoverlay> * 参考并不断重新分配它对我来说感觉有点奇怪。

4

1 回答 1

2

这里似乎有三个问题:

  1. 如何检测服务器中点的变化?

    这样做的丑陋方法是遍历您的位置并查看coordinate和/或是否radius更改。更好的做法是让服务器更新创建、修改和删除时间戳或其他标识符,以便客户端能够检索自上次更新以来的所有创建、修改和/或删除。最好的办法是将其与某种形式的推送通知结合起来,这样客户端也会主动收到这些更改的通知。

    这个问题很难抽象地回答。这在很大程度上取决于您的服务器的功能和数据库的性质(例如,有多少“点”,它们更改的频率等)。这既影响客户端-服务器架构,也影响客户端实现。

  2. 地点变化时如何更新地图?

    这是一个容易得多的问题。插入和删除很容易。您只需执行addOverlay:(或者,在 iOS 7addOverlay:level:removeOverlay:. 对于更新,虽然它不优雅,但我认为最简单的方法是删除旧的叠加层并将其重新添加,并viewForOverlay为您处理用户界面。

  3. 类的正确结构是Spot什么?

    就像一个想法,但是拥有你的coordinateandradius属性,然后也拥有一个id<MKOverlay> overlay对象似乎是重复的(因为这可能是 aMKCircle具有相同的两个属性)。如果您的叠加层将成为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
    

    然后,您需要做的就是实现boundingMapRectand 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在您MKMapViewDelegate的 .

    - (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;
    

    然后您可以定义boundingMapRectcoordinate返回适当的值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 回答