You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mapbox+SwiftUI:UI刷新无法传递至updateUIView()问题咨询

Mapbox SwiftUI: updateUIView() Not Triggering When @State Array Count Is Displayed in Text

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 23:47:27