ios - 在 MKMapView 上更新和组织覆盖

标签 ios objective-c dictionary overlay

我想在 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

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

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

是否有更好的方法来跟踪叠加层?保持 NSObject<MKoverlay> *每个位置都附有引用并不断重新分配,这让我觉得有点奇怪。

最佳答案

这里好像有3个问题:

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

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

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

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

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

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

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

    然后,您需要做的就是执行boundingMapRectintersectsMapRect :

    - (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 ,例如,在 iOS 7 之前的版本中,这将是:

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

    然后你可以定义boundingMapRectcoordinateMKCircle 返回适当的值(使您不必自己编写):

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

希望对您有所帮助。

关于ios - 在 MKMapView 上更新和组织覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16501587/

相关文章:

ios - 访问 UIWindow XCode UITesting 上的元素

ios - UILabel 导致应用程序在添加到 View 时崩溃(仅限 Xcode 6 和 iOS 8)

ios - iOS8.0中UITableViewRowAction如何管理等宽?(更多,删除等操作)

ios - 将数据从数组加载到 UITableView 单元格

ios - 如何在准备 segue 时传递位置和图像

Python memoryerror 创建大字典

javascript - 如何使用javascript将字典列表中的数字字符串转换为整数?

c# - 当 Key 等于订单号时,如何在字典中移动项目?

ios - 命令/usr/bin/codesign 失败,退出代码为 5

ios - 同时关闭一个 View Controller 然后呈现一个