【问题标题】:SwiftUI Map causes "modifying state during view update"SwiftUI Map 导致“在视图更新期间修改状态”
【发布时间】:2022-11-13 23:17:18
【问题描述】:

我想实现一个基本的地图视图,当他们点击一个按钮时,它将以用户的位置为中心,类似于 Apple 地图应用程序。我尝试了以下操作,但每当我点击按钮时,[SwiftUI] Modifying state during view update, this will cause undefined behavior. 就会打印在控制台中。在我看来,更新 tracking 状态变量会导致错误。但是,我不确定状态变量还打算如何使用。尽管打印了错误,但该应用程序确实按预期运行。有没有人有这方面的经验或知道可能出了什么问题?

struct ContentView: View {
    @State var region: MKCoordinateRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 47.3769, longitude: 8.5417), latitudinalMeters: 2000, longitudinalMeters: 2000)
    @State var tracking = MapUserTrackingMode.follow
    
    var body: some View {
        ZStack {
            Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true, userTrackingMode: $tracking)
                .ignoresSafeArea()
                .task {
                    let locationManager = CLLocationManager()
                    locationManager.requestWhenInUseAuthorization();
                }
            Button {
                tracking = .follow
            } label: {
                Image(systemName: tracking == .follow ? "location.fill" : "location")
                    .padding()
            }
            .background(.white)
        }
    }
}

【问题讨论】:

    标签: swiftui runtime-error mapkit


    【解决方案1】:

    在我看来,这是 Map 中的一个错误(从 Xcode 版本 13.3.1 (13E500a) 和 iPhone 13 模拟器开始)。如果切换到 Breakpoints 侧栏并单击 + 并添加一个 All Runtime Issues 断点,如果您调试并单击该按钮,您将点击断点并看到:

    此跟踪显示,当点击按钮以更改跟踪状态时,SwiftUI 通过调用 _setUserTrackingMode(第 13 行)将 MKMapView 更新为新状态,但此操作的副作用是回调到 mapLayerDidChangeVisibleRegion(第 9 行)并尝试设置 Binding 的值(第 6 行),很可能是 coordinateRegion。它不应该在从状态更新 MKMapView 时设置绑定,这是导致警告的原因。我们都应该报告这个错误 - 我在开发人员工具 - SwiftUI 下将其提交为 FB9990674,请随时参考我的号码。

    【讨论】:

    • 谢谢你的解释,这让我发疯:)
    【解决方案2】:

    迁移到 iOS 16(Xcode 14.1)时,我开始遇到类似的问题。 就我而言,我有以下内容:

    // LocationView
    
    struct LocationView : View {
    
        @StateObject private var viewModel : ViewModel
    
        var body: some View {
    
            Map(coordinateRegion: $viewModel.region)
                .clipShape(RoundedRectangle(cornerRadius: 10))
        }
    }
    
    
    // View Model
    
    @MainActor final class ViewModel : ObservableObject {
    
        ...
    
        @Published var region : MKCoordinateRegion
    
        ...
    }
    

    在这种情况下,我为删除警告所做的是在 View 中为 viewModel 中的 Published 属性创建一个 Binding

    private var region : Binding<MKCoordinateRegion> {
            
        Binding {
                
            viewModel.region
                
        } set: { region in
                
            DispatchQueue.main.async {
                viewModel.region = region
            }
        }
    } 
    

    然后更改视图以使用此绑定而不是 viewModel 中的已发布变量:

        Map(coordinateRegion: region)
    

    应用程序继续按预期工作,错误/警告不再出现。

    【讨论】:

      猜你喜欢
      • 2020-06-12
      • 1970-01-01
      • 2019-12-17
      • 2021-09-17
      • 2023-02-06
      • 2021-01-10
      • 2020-03-11
      • 2020-05-15
      • 1970-01-01
      相关资源
      最近更新 更多