1

I am using MapView this way (the code is of course simplified):

struct IkMapView: UIViewRepresentable {
  var mapView = MKMapView()

  func makeUIView(context: Context) -> MKMapView {
    mapView.delegate = context.coordinator
    return mapView
  }

  public func unselectAllSpots() {
    // mapView is useless and not the actual map view I am seeing
    for annotation in mapView.annotations {
      mapView.deselectAnnotation(annotation, animated: false)
    }
  }

  func updateUIView(_ view: MKMapView, context: Context) {
    // this view is good
  }

  func makeCoordinator() -> Coordinator {
    Coordinator(self)
  }
  
  class Coordinator: NSObject, MKMapViewDelegate, UIGestureRecognizerDelegate {
    var parent: IkMapView
    
    init(_ parent: IkMapView) {
      self.parent = parent
      super.init()
    }
  }
}

I would like to expose a few public functions to allow actions from the parent view, for example, here, it is the unselectAllSpots() function. However, when I call it from the parent, the mapView is not the same one as the one I get through updateUIView(), and it doesn't actually impact the map. I have read somewhere that the actual displayed mapView is not that instance (but the instance we get in updateUIView().

What's the best way to solve this? I could transform my struct into a class and create a new MKMapView property which I would associate to the map view I get through updateUIView but that doesn't feel right at all.

Thanks a lot for your help :)

TigrouMeow
  • 3,669
  • 3
  • 27
  • 31

1 Answers1

2

A representable is updated on changed external states, so a possible approach is to do needed changes on binding changes, like

struct IkMapView: UIViewRepresentable {
    @Binding var unselectAll: Bool       // << activates update

    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()        // create here !!
        mapView.delegate = context.coordinator
        return mapView
    }

    func updateUIView(_ mapView: MKMapView, context: Context) {
        if unselectAll {                // << handle state
            for annotation in mapView.annotations {
                mapView.deselectAnnotation(annotation, animated: false)
            }
            unselectAll = false
        }
    }

// .. other code
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • I didn't say but that is actually what I am doing now as a workaround... so I have variables like "requestCenterLocation", "requestUnselectLocation" but that didn't feel right... also, I don't think SwiftUI recommends changing the value of the bindings during an visual update. So I still wonder if this is the best? :) – TigrouMeow May 20 '22 at 01:30