Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I update the location of an MKAnnotation object on a mapView?

I have the following code, which aims to loop through all the annotations on the current apple map view and update their location coordinates.

for existingMarker in self.mapView.annotations {

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

Sadly this is not allowed. I am told that 'coordinate' is a get only property. So this is obviously not how I am meant to update the MKAnnotation's location of annotations already drawn on a mapView. How can I do this then? Specifically I would like to do this and have the map "redraw" with the new coordinates ASAP. I am sure this must be possible as it seems like a common use case.

like image 653
sometimesiwritecode Avatar asked May 28 '17 23:05

sometimesiwritecode


1 Answers

The issue is that annotations is an array of MKAnnotation. But this protocol only requires that there is a coordinate property, but doesn’t dictate that it is a variable. Note the absence of set in the protocol:

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 }

    ...
}

So, when iterating through the annotations of the MKMapView, which is defined as an array of MKAnnotation, it doesn’t know that your coordinate is a variable or a constant, and generates that warning.

But, let’s imagine that your annotations were MKPointAnnotation. In that concrete annotation type, the coordinate is a variable, not a constant. So you can be specific about the type. For example:

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

Or

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

Obviously, you if you define your own annotation class that conforms to MKAnnotation, obviously:

  • define coordinate as a variable, not a constant; and

  • make sure it’s dynamic.

Thus:

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

And then the pattern is the same as above, except reference your class, e.g.:

mapView.annotations
    .compactMap { $0 as? MyAnnotation }
    .forEach { existingMarker in
        existingMarker.coordinate = CLLocationCoordinate2D(latitude: 12.12121212, longitude: 14.312121121)
}
like image 125
Rob Avatar answered Sep 28 '22 07:09

Rob