Chris
Chris

Reputation: 247

Is it possible to change MKAnnotation Coordinates without knowing variable name?

I appreciate the question might seem odd but basically I am adding annotations to the map after pulling coordinates from a backend database. The amount of annotations being added vary depending on the user.

let details = Annotation(title: "\(userName)",
                                         locationName: "",
                                         coordinate: CLLocationCoordinate2D(latitude:convertLat!, longitude: convertlon!))

                self.mapView.addAnnotation(details as MKAnnotation)
                self.mapView.selectAnnotation(details, animated: true)

The trouble I am having is I would like to update the coordinates of the 'details' annotation at specific intervals but I am unable to access the 'details' annotation because of course it is out of scope.

Is it possible, for example, to access an annotation through its title name and change its coordinates accordingly?

The other alternative is to remove all annotations and recreate them with the updated coordinates but this is something I am trying to avoid.

It's probably worth noting that for a number of reasons I can't just simply create the details annotation outside off my methods.

Thanks.

UPDATED So I'm trying a slightly different approach that looks like this:

for annotation in mapView.annotations as [MKAnnotation] {

        if (annotation as AnyObject).title == "Title of annotation"   {

           annotation.title = "Change to something else"

    }
}

However I am unable to change the title as Swift is telling me it's a 'get only' property and I don't understand why.

Adding annotation to the mapView:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

   // if (annotation is MKUserLocation) { return nil }

    let reuseID = "icon"
    var v = mapView.dequeueReusableAnnotationView(withIdentifier: reuseID)

    if v != nil {

        v?.annotation = annotation

    } else {

        v = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
        v?.image = snapShotImage
        v?.canShowCallout = true
}

 return v

}

Upvotes: 5

Views: 1521

Answers (5)

Jeffrey Morgan
Jeffrey Morgan

Reputation: 566

You need to cast the annotations to your own Annotation class rather than the MKAnnotation protocol:

if let annotations = mapView.annotations as? [Annotation] {
  for annotation in annotations {
    if annotation.title == "Title of annotation"   {
      annotation.title = "Change to something else"
    }
  }
}

The MKAnnotation protocol only specifies a getter for the title property, which is why casting to an MKAnnotation doesn't let you change the title.

Upvotes: 2

pkc
pkc

Reputation: 8516

Create subclass of MKAnnotation.

class CustomAnnotation: MKAnnotation {
    var _title: String = "Title of annotation"
    override var title: String {
        get {
            return _title
        }
        set {
            self._title = newValue
        }
    }
}

Now when create annotation using your custom class.

let details = CustomAnnotation(title: "\(userName)",
                                         locationName: "",
                                         coordinate: CLLocationCoordinate2D(latitude:convertLat!, longitude: convertlon!))

As you have getter and setter methods for title property, now you can update the specific or all annotations (as you did using for-in loop;as stated in your question).

Upvotes: 3

Ron Diel
Ron Diel

Reputation: 1424

I understand your hesitation to remove and replace all of the annotations, but now that you have identified the specific annotation in question, why not just delete, recreate, and re-add that one inside the for loop you're showing:

let replacement = annotation
replacement.title = "Change to something else"
self.mapView.addAnnotation(replacement)
mapView.removeAnnotation(annotation)

Upvotes: 2

Wain
Wain

Reputation: 119041

You don't edit the annotation, you replace it. Ideally you'd keep a reference to the annotation so you can just remove it and then create and add a new one (and update the reference to that new annotation). If you don't want to do that for some reason then you can use your loop to find the correct annotation to remove and then create and add the new one.

Upvotes: 2

pbc
pbc

Reputation: 525

Without knowing the structure of the source class that holds the coordinates, you could create a class that contains both the source object and the created MKAnnotation. This class will use KVO via addObserver to observe any changes in the source coordinates and then apply them to the annotation: the same could be done for title/subtitles. Add the created annotation to the map as normal. Make sure that instances of the above class are retained by the view controller that owns the mapView so ARC doesn't reclaim everything!

Assuming you can still access and update the source, the UI will look after itself.

Upvotes: 2

Related Questions