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