如何从 MKMapView didSelect 注释更新封装的 SwiftUI 视图

How to update encapsulating SwiftUI View from MKMapView didSelect annotation

从 MKMapKit didSelect 注释委托中将更新推送到封装 SwiftUI 视图的合适方法是什么?

struct CompoundView: View {
  @State private var selected: MKAnnotation?
  
  var body: some View {
    ZStack {
      MapView(annotations: annotations, selected: $selected)
      if let selected = selected {
        PopUpView(selected)
      }
    }
  }
}

MapView 作为 UIViewRepresentable 实现,代表:

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
  subject.selected = view.annotation // subject is the controller's reference to the MapView wrapping MKMapView 
}

将回调传递给更新 CompoundView 状态的委托会导致 XCode 触发 Modifying state during view update, this will cause undefined behavior. 它还会阻止 MKMapView 中的注释引脚被可见选择(图钉图标在第一次被点击时不会变大)。

类似地,将绑定从 CompoundView 传递到 MapView 似乎有问题,因为在点击时图钉图标不会增长的问题仍然存在。我假设由于状态更改时正在重建父视图。

我试过在 DispatchQueue.main.async 调用中包装委托逻辑,但没有成功,此时我只是在猜测。

是否有更好的方法从 MKMapView 委托调用中将信息反馈给父视图,这样我们既不在视图更新中,也不阻止地图注释在点击时正常动画?

编辑:事实证明,我的注释在选择时没有动画的问题的根源是每当视图更新时我都在不断刷新注释。在 makeUIView 中添加注释并将 updateUIView 留空解决了很多奇怪的交互问题。

func updateUIView(_ map: MKMapView, context: Context) {
  map.removeAnnotations(map.annotations)
  map.addAnnotations(annotations)
}

通过使用 ObservableObject,我能够让两个视图都很好地发挥作用。该对象将 @Published 父视图使用 @ObservedObject(或@StateObject)订阅的选定注释。然后,地图视图从委托调用中更新了可观察对象的注释 class 成员。请注意,地图视图不会将对象标记为 @ObservedObject,因为当模型更改时地图视图不应更新(这会导致地图注释出现错误并且不会在选择和取消选择时设置动画)。