Refresh MKAnnotationView on a MKMapView

Viewed 33703

I'd like to a-synchronically load images for my custom MKAnnotationView; I'm already using the EGOImageView-framework (it goes very well with UITableViews), but I fail to make it work on MKMapView. Images seem to be loaded, but I cannot refresh them on the map - [myMap setNeedsDisplay] does nothing.

7 Answers

Thank you @Vladimir for the help! Your answer inspired my answer. I made some changes to make it clearer.

func addAnnotation(coordinate: CLLocationCoordinate2D) {
    let annotation = Annotation()
    annotation.coordinate = coordinate
    annotations.append(annotation)
    mapView.addAnnotation(annotation)
    for index in 0..<annotations.count {
        if let view = mapView.view(for: annotations[index]) as? AnnotationView {
            if index == 0 {
                view.imageView.image = NSImage(named: "icon_positioning")
            } else {
                view.imageView.image = NSImage(named: "icon_positioning")
            }
        }
    }
}

Also the protocol in MKMapview needs to implement:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    let view = mapView.dequeueReusable(withClass: AnnotationView.self, annotation: annotation)
    if index == 0 {
        view.imageView.image = NSImage(named: "icon_positioning")
    } else {
        view.imageView.image = NSImage(named: "icon_positioning")
    }
    return view
}

By the way, the AnnotationView initialization here is:

public extension MKMapView {
    func dequeueReusable<T: MKAnnotationView>(withClass name: T.Type,annotation: MKAnnotation?) -> T {
        if let view = dequeueReusableAnnotationView(withIdentifier: T.identifier()) as? T {
            return view
        }
        let view = T.init(annotation: annotation, reuseIdentifier: T.identifier())
        return view
    }
}

Thanks again @Vladimir for the answer

I wanted to refresh user location pin with new selected avatar. I found another fast solution for that case. I have 2 screens. The first one is for selecting avatar and the second is for displaying user on map.

swift 5 You can change user location image by creating MKAnnotationView

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

    if annotation is MKUserLocation {
        let userIdentifier = "UserLocation"
        var userView = mapView.dequeueReusableAnnotationView(withIdentifier: userIdentifier)
        if userView == nil {
            userView = MKAnnotationView(annotation: annotation, reuseIdentifier: userIdentifier)
        } else {
            userView?.annotation = annotation
        }

        userView!.image = UIImage(named: "avatar1") //your image

        return userView
    }

    return nil
 }

So if user will change avatar to something else, for example to "avatar2" it won't refresh.

In order to refresh user location image i added this code in viewWillAppear()

 self.mapView.showsUserLocation = false
 self.mapView.showsUserLocation = true
Related