Search code examples
iosswiftuiuikit

MKMapView.annotations array is empty after creating annotations


I have a SwiftUI project with a wrapped UIKit MapKit component for displaying annotations on a map. These annotations generate and call their respective delegate methods just fine (for example, the didSelect event). However, I need to update these markers on a updateUIView method that gets called when a binding is updated.

The issue I have is that the updateUIView gets called correctly when the binding gets updated, however I cannot access the MKMapView instances' annotations array, it is empty after I have created the annotations.

func updateUIView(_ uiViewController: MKMapView, context: Context) {
    self.UpdateUIMarker()
}

func UpdateUIMarker() {
    print(self.map.annotations.count)
}

On initial load of the map, the console does correctly print that there are 4 annotations associated with the MKMapView instance, however on subsequent method calls the console prints out a count of 0.

This is the binding

@Binding var ui_markers: [UIMarker]

And the respective MKAnnotation class I have defined

class UIMarker: NSObject, MKAnnotation, ObservableObject {
    public var coordinate: CLLocationCoordinate2D
    public var nr: Int
    @Published public var complete: Bool

    init(coordinate: CLLocationCoordinate2D, nr: Int, complete: Bool) {
        self.coordinate = coordinate
        self.nr = nr
        self.complete = complete
    
        super.init()
    }
}

Additionally, this is the delegate method for annotations in the Coordinator

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        guard let ui_marker = annotation as? UIMarker else { return nil }
        
        var view = mapView.dequeueReusableAnnotationView(withIdentifier: "POI")
        
        if view == nil {
            view = MKAnnotationView(annotation: ui_marker, reuseIdentifier: "POI")
        }
        
        view?.image = UIImage(named: ui_marker.complete ? "map-marker-visited" : "map-marker")
        view?.frame.size = CGSize(width: 35, height: 35)
        
        return view
}

The goal is as follows: an annotation is updated in the ui_markers binding array (the state of the property completed in a UIMarker is changed), the updateUIView picks up this change and changes the image of the respective MKAnnotation. So far, the updateUIView gets called correctly when the binding is updated and I can see which annotations have been completed in the ui_markers array, the problem is in accessing that annotation in the MKMapView.annotations array as the entire array seemingly gets emptied shortly after creation.

Let me know if additional info is required, and apologies in advance if I have missed something obvious, I am still very inexperienced with UIViewRepresentable and UIKit.


Solution

  • Solved: the issue was that inside the updateUIView method, I was working with the MKMapView instance that I had assigned to the class itself. Instead, all I needed to do was work with the MKMapView instance that was passed into the updateUIView method like this:

    func updateUIView(_ uiViewController: MKMapView, context: Context) {
        self.UpdateUIMarker(map: uiViewController)
    }
        
    func UpdateUIMarker(map: MKMapView) {
        ///Instead of self.map.annotations, use map.annotations
        print(map.annotations.count)
    }