【问题标题】:How do I update the location of an MKAnnotation object on a mapView?如何更新 MKAnnotation 对象在 mapView 上的位置?
【发布时间】:2017-10-29 04:37:46
【问题描述】:

我有以下代码,旨在循环当前苹果地图视图上的所有注释并更新它们的位置坐标。

for existingMarker in self.mapView.annotations {

    existingMarker.coordinate.latitude = 12.12121212
    existingMarker.coordinate.longitude = 14.312121121          
}

遗憾的是这是不允许的。有人告诉我“坐标”是一个只能获取的属性。因此,这显然不是我打算更新已在 mapView 上绘制的 MKAnnotation 的注释位置的方式。那我该怎么做呢?具体来说,我想这样做并尽快用新坐标“重绘”地图。我相信这一定是可能的,因为它似乎是一个常见的用例。

【问题讨论】:

    标签: ios swift mkannotation cllocation apple-maps


    【解决方案1】:

    问题在于annotationsMKAnnotation 的数组。但是这个协议只要求有一个coordinate 属性,但并不规定它是一个变量。注意协议中没有set

    public protocol MKAnnotation : NSObjectProtocol {
    
        // Center latitude and longitude of the annotation view.
        // The implementation of this property must be KVO compliant.
        var coordinate: CLLocationCoordinate2D { get }
    
        ...
    }
    

    因此,当迭代MKMapViewannotations(定义为MKAnnotation 的数组)时,它不知道您的坐标是变量还是常量,并生成该警告。

    但是,让我们假设您的注释是MKPointAnnotation。在那个具体的注释类型中,coordinate 一个变量,而不是一个常量。因此,您可以具体说明类型。例如:

    for annotation in mapView.annotations {
        if let annotation = annotation as? MKPointAnnotation {
            annotation.coordinate = CLLocationCoordinate2D(latitude: 12.12121212, longitude: 14.312121121)
        }
    }
    

    或者

    mapView.annotations
        .compactMap { $0 as? MKPointAnnotation }
        .forEach { existingMarker in
            existingMarker.coordinate = CLLocationCoordinate2D(latitude: 12.12121212, longitude: 14.312121121)
    }
    

    很明显,如果你定义了自己的符合MKAnnotation的注解类,显然:

    • coordinate定义为变量,而不是常量;和

    • 确保它是dynamic

    因此:

    class MyAnnotation: NSObject, MKAnnotation {
        dynamic var coordinate: CLLocationCoordinate2D
        dynamic var title: String?
        dynamic var subtitle: String?
    
        // other properties unique to your annotation here
    
        init(coordinate: CLLocationCoordinate2D, title: String? = nil, subtitle: String? = nil) {
            self.coordinate = coordinate
            self.title = title
            self.subtitle = subtitle
    
            super.init()
        }
    }
    

    然后模式和上面一样,除了引用你的类,例如:

    mapView.annotations
        .compactMap { $0 as? MyAnnotation }
        .forEach { existingMarker in
            existingMarker.coordinate = CLLocationCoordinate2D(latitude: 12.12121212, longitude: 14.312121121)
    }
    

    【讨论】:

    • 不幸的是,在 SWIFT 4.0 上你不能再这样做了,特别是关于动态坐标的事情给了我一个错误 Cannot override with a stored property 'coordinate'
    • 注意,我没有子类化现有的注释类型。我创建了自己的。这消除了“覆盖存储的属性”问题。但是你实际上不必定义自己的类型,如果你不想,你只需要指定 coordinate 真正是一个变量的具体类型。 MKAnnotation 协议只要求 coordinate 存在,但不要求它是一个变量。但是例如MKPointAnnotation 将其声明为变量,因此您可以根据需要按原样使用它。我已经相应地更新了我的答案。
    • @JBarros35 - 至少在 Swift 5 中,您可以将坐标设置为 var(可变)并设置它。您只需确保将 MKAnnotation 转换为您的新类(让 myAnnotation = mkAnnotation as?MyAnnotation)能够看到并允许您进行变异。
    • 这使得注解可变,但如果相应的注解视图已经显示在地图上并且您希望注解视图在更改注解坐标时移动,则必须使该可变坐标dynamic ,否则注释视图不会随着坐标的变化而自动移动。注释视图通过 KVO 观察变化。
    【解决方案2】:

    对于 Swift,您只需将坐标字段设为 var,然后在尝试变异时键入 MKAnnotation:

    protocol MutableAnnotation : NSObject, MKAnnotation {
        dynamic var coordinate: CLLocationCoordinate2D { get set }
    }
    
    class MyAnnotation : MutableAnnotation {
        dynamic var coordinate: CLLocationCoordinate2D
    }
    
    // ...
    
    func updateLocation(_ annotation: MKAnnotation, coordinate: CLLocationCoordinate2D)
    {
        guard let mutable = annotation as? MutableAnnotation else { return }
        mutable.coordinate = coordinate
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多