Custom MKAnnotationView - UIImage does not appear

Hello everybody,

I am trying to create a custom annotation for a map view. Everything works perfectly, except for the UIImage I am trying to show that does not appear.

I think I am not being able to show the MKAnnotationView I am trying to set.

In the mapView method I am not being able to perform that print statement. I can't figure out why.

Code Block
import SwiftUI
import UIKit
import MapKit
class ObservationAnnotation: NSObject, MKAnnotation {
    
    let coordinate: CLLocationCoordinate2D
    let title: String?
    let subtitle: String?
    var image: UIImage?
    
    init(coordinate: CLLocationCoordinate2D, species: String, image: UIImage, confidence: Double) {
        self.coordinate = coordinate
        self.title = species
        self.subtitle = "Confidence: \(confidence)"
        self.image = image
    }
}
class ObservationAnnotationView: MKAnnotationView {
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        guard
            let observationAnnotation = self.annotation as? ObservationAnnotation else {
            return
        }
        
        image = observationAnnotation.image
    }
}
struct MyObservationsMap: UIViewRepresentable {
    
    var observationList: [Observation]
    
    func makeUIView(context: Context) -> MKMapView {
        MKMapView.init(frame: .zero)
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        
        for observation in observationList {
            
            let annotation = ObservationAnnotation(
                coordinate: CLLocationCoordinate2D(latitude: observation.latitude, longitude: observation.longitude),
                species: observation.speciesName!,
                image: UIImage(data: observation.image!)!,
                confidence: observation.confidence
            )
            
            uiView.addAnnotation(annotation)
        }
    }
    
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        
        let reuseId = "observation"
        let annotationView = ObservationAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        annotationView.canShowCallout = true
        
        print("Here")
        
        return annotationView
    }
}


Thank you!

In the mapView method I am not being able to perform that print statement. I can't figure out why.

You are not setting delegate when you instantiate a MKMapView.
The method mapView(_:viewFor:) is a method declared in MKMapViewDelegate, unless setting delegate to MKMapView, it is not called.

You need to define a class which works as a delegate of MKMapView,
move the method mapView(_:viewFor:) into the class,
and set the instance of it when instantiating a MKMapView.


One more thing, you should better use dequeueReusableAnnotationView(withIdentifier:), for performance reason.
To utilize it, your code should be ready for reuse an MKAnnotationView which is instantiated with annotation nil.

Your code would look like this:

Code Block
class ObservationAnnotationView: MKAnnotationView {
//No subclassing needed...
}
struct MyObservationsMap: UIViewRepresentable {
var observationList: [Observation]
static let reuseId = "observation"
//Define a class which works as a delegate
class MyMapViewDelegate: NSObject, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId, for: annotation) as! ObservationAnnotationView
if let observationAnnotation = annotation as? ObservationAnnotation {
annotationView.image = observationAnnotation.image
}
annotationView.canShowCallout = true
print("Here")
return annotationView
}
}
//Instantiate the delegate class
var mapViewDelegate: MKMapViewDelegate = MyMapViewDelegate()
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView(frame: .zero)
mapView.delegate = mapViewDelegate //<- Set delegate
mapView.register(ObservationAnnotationView.self, forAnnotationViewWithReuseIdentifier: MyObservationsMap.reuseId)
addAnnotations(to: mapView)
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
//No need to add annotations here...
}
func addAnnotations(to mapView: MKMapView) {
for observation in observationList {
let annotation = ObservationAnnotation(
coordinate: CLLocationCoordinate2D(latitude: observation.latitude, longitude: observation.longitude),
species: observation.speciesName!,
image: UIImage(data: observation.image!)!,
confidence: observation.confidence
)
mapView.addAnnotation(annotation)
}
}
//...
}


Custom MKAnnotationView - UIImage does not appear
 
 
Q