【问题标题】:Model updates trigger "Publishing changes from within view updates is not allowed" error when using Map in SwiftUI在 SwiftUI 中使用 Map 时,模型更新触发“不允许从视图更新中发布更改”错误
【发布时间】:2022-10-02 00:19:20
【问题描述】:

我正在使用下面的代码来执行以下操作。

  1. 每 5 秒创建一个新项目并将其附加到模型
  2. 在 listView 中显示项目列表
  3. 在mapView中显示项目的地图

    如果我在 listView 中,列表会每 5 秒正确更新一次新项目。没有错误信息。 如果我在 mapView 中,地图也会更新(每 5 秒一个新标记),但我收到错误“[SwiftUI] 不允许从视图更新中发布更改,这将导致未定义的行为。\” 由于 list 和 map 都显示相同的模型数据,我想知道为什么 map 抱怨而 list 没有。实际的模型更新在主角身上,所以它为什么抱怨。

    任何想法?

    //Model
    struct TestApp1Model {
        struct TestItem: Identifiable {
            var id = UUID()
            var name: String
            var latitude: Double
            var longitude: Double
        }
    
        var items = [TestItem]()
    }
    
    // ViewModel
    class TestApp1ViewModel: ObservableObject {
        @Published private var model = TestApp1Model()
        private var timer:Timer?
     
        init() {
            timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { _ in
                Task { @MainActor in
                    self.addItem()
                }
            }
        }
        
        var items:[TestApp1Model.TestItem] {
            model.items
        }
        
        @MainActor func addItem () {
            let name = \"Item \" + model.items.count.description
            let latitude = Double.random(in: 45...55)
            let longitude = Double.random(in: 5...11)
            model.items.append(TestApp1Model.TestItem(name: name, latitude: latitude, longitude: longitude))
        }
    }
    
    // View
    struct TestApp1View: View {
        @StateObject var testVM = TestApp1ViewModel()
        @State var region:MKCoordinateRegion
        
        init() {
            self.region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 50, longitude: 8), span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 6))
        }
        
        var body: some View {
            TabView {
                listView
                    .tabItem {
                        Image(systemName: \"list.bullet\")
                        Text(\"List\")
                    }
                    .backgroundStyle(Color.white)
                mapView
                    .tabItem {
                        Image(systemName: \"map\")
                        Text(\"Map\")
                    }
                    .backgroundStyle(Color.white)
            }
        }
        
        var listView: some View {
            VStack {
                List (testVM.items) { item in
                    HStack {
                        Text(item.name)
                        Text(item.latitude.description)
                        Text(item.longitude.description)
                   }
                }
            }
        }
    
        var mapView: some View {
            Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true,annotationItems: testVM.items) {item in
                MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: item.latitude, longitude: item.longitude)) {
                    Image(systemName: \"plus\")
                        .foregroundColor(.red)
                }
            }
            .ignoresSafeArea()
        }
    }
    

    标签: swift swiftui mapkit publish-subscribe xcode14


    【解决方案1】:

    您应该发布您的项目数组,而不是模型。

    struct TestItem: Identifiable {
        let id = UUID()
        var name: String
        var latitude: Double
        var longitude: Double
    }
    
    class Model: ObservableObject {
        @Published var items = [TestItem]()
        private var timer: Timer?
    
        init() {
            timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { _ in
                Task { @MainActor in
                    self.addItem()
                }
            }
        }
    
        @MainActor func addItem () {
            let name = "Item " + items.count.description
            let latitude = Double.random(in: 45...55)
            let longitude = Double.random(in: 5...11)
            items.append(TestItem(name: name, latitude: latitude, longitude: longitude))
        }
    }
    

    现在,每次添加新项目时,您的视图都会更新。

    【讨论】:

    • 我的观点确实更新了。每次模型中的任何内容发生更改时,@Published 都会触发更新。问题不在于视图不更新,而是 mapView 中的更新会创建上述错误消息。但是,我已根据您的建议更改了代码,结果完全相同。
    • 你有比这更多的代码吗?我根本没有收到那个错误。
    • 这是整个项目(进口和 cmets 除外)。完整的项目在这里:link。错误出现在运行时,而不是编译时。我使用的是 Xcode 14,开发目标是 IOS 16.0。
    【解决方案2】:

    我在 SwiftUI 的 Map 上遇到过类似的问题,以至于我确信这是一个错误。在我遇到的情况下,地图上的每个注释都会出现一次警告消息,即使注释没有更改但由于已发布属性的更改而正在重绘视图也是如此。我放弃了 SwiftUI 的 Map。回到 MKMapView - 更好的支持和所有这些警告都消失了。

    【讨论】:

      猜你喜欢
      • 2022-10-04
      • 2023-02-01
      • 2022-09-28
      • 2023-02-04
      • 1970-01-01
      • 2020-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多