Mapbox+SwiftUI:UI刷新无法传递至updateUIView()问题咨询
This is a tricky edge case with SwiftUI's dependency tracking, combined with how Mapbox's UIViewRepresentable wrapper interacts with reference-type elements in your array. Let's break down what's happening and how to fix it:
What's Causing the Issue?
When you add Text("\(self.annotations.count)") to your button label, SwiftUI's view update optimization prioritizes updating only the parts of the view hierarchy that directly depend on the count property of your annotations array.
Since MGLPointAnnotation is a reference type (subclass of NSObject), SwiftUI might not reliably detect that the entire array's content has changed when you append a new annotation—especially when another view is only tracking the array's count rather than the full array content. This leads to the MapView's updateUIView() method not being called, even though the array itself has updated.
Fixes You Can Try
1. Wrap Annotations in an ObservableObject
Using ObservableObject with @Published provides more explicit change notifications than @State for complex data structures, ensuring all dependent views (including your MapView) get notified when the array updates.
import SwiftUI import Mapbox class MapViewModel: ObservableObject { @Published var annotations: [MGLPointAnnotation] = [ MGLPointAnnotation(title: "Mapbox", coordinate: .init(latitude: 37.791434, longitude: -122.396267)) ] } struct ContentView: View { @StateObject var viewModel = MapViewModel() var body: some View { ZStack { VStack { MapView(annotations: $viewModel.annotations) .centerCoordinate(.init(latitude: 37.791293, longitude: -122.396324)) .zoomLevel(16) Button(action: { let rand = Float.random(in: 37.79...37.80) viewModel.annotations.append(MGLPointAnnotation(title: "Mapbox", coordinate: .init(latitude: CLLocationDegrees(rand), longitude: -122.396261))) }) { Text("Button") Text("\(viewModel.annotations.count)") } } } } }
2. Force MapView Updates with .id()
Add an .id() modifier to your MapView that ties its identity to the annotation count. This tells SwiftUI to recreate the MapView whenever the count changes, guaranteeing updateUIView() runs:
MapView(annotations: $annotations) .centerCoordinate(.init(latitude: 37.791293, longitude: -122.396324)) .zoomLevel(16) .id(annotations.count) // Triggers reinitialization on count change
3. Simplify updateUIView() Logic
If your MapView implementation uses a coordinator to cache old annotations and only updates when the array "changes", remove that conditional check. Since reference-type elements can cause equality checks to fail unexpectedly, just force-update the annotations every time updateUIView() is called:
func updateUIView(_ uiView: MGLMapView, context: Context) { // Skip equality checks and directly refresh annotations uiView.removeAnnotations(uiView.annotations ?? []) uiView.addAnnotations(annotations) }
内容的提问来源于stack exchange,提问作者Marcio Cabral

