SwiftUI UserDefaults 干扰 Firebase Firestore 数据

SwiftUI UserDefaults interfering with Firebase Firestore data

我正在将 Google Firebase 的 Cloud Firestore 服务与 SwiftUI 项目一起使用,该项目详细介绍了电子游戏中每张地图的策略。我正在使用 View、ViewModel、Model 架构。可能还值得注意的是,我正在使用 Swift 包管理器而不是 CocoaPods 来导入 API。

我有一个 ScrollView,其中包含从 Firestore 集合中获取的一些地图。点击地图将向用户显示另一个滚动视图,其中列出了从 Firestore 中的单独集合中获取的策略。我遇到的问题是,每当更改 UserDefault(使用 UserDefaults.standard.setValue(...)@AppStorage("settingName") var...)时,ScrollView 的内容就会消失。 Firestore 数据和 UserDefaults 之间没有关系(没有任何内容从一个保存到另一个)。

尽管代码从一个 ViewModel swift 文件复制并粘贴到另一个文件,但此 发生在详细视图中,而不是主视图中。

这是 StratsViewModel.swift 代码:

class StratsViewModel: ObservableObject {

    @Published var strats = [Strat]()

    private var db = Firestore.firestore()

    func fetchData(forMap: String) {
    
        if strats.isEmpty {
        
            db.collection("maps/\(forMap)/strats").getDocuments { (querySnapshot, error) in
            
                guard let documents = querySnapshot?.documents else {
                
                    return
                
                }
            
                self.strats = documents.map { (queryDocumentSnapshot) -> Strat in
                
                    let data = queryDocumentSnapshot.data()
                
                    let id = queryDocumentSnapshot.documentID
                
                    let name = data["name"] as? String ?? ""
                    let map = data["map"] as? String ?? ""
                    let type = data["type"] as? String ?? ""
                    let side = data["side"] as? String ?? ""
                
                    let strat = Strat(id: id, name: name, map: map, type: type, side: side)
                
                    return strat
                
                }
            
            }
        
        }
    
    }

}

在MapsDetailView.swift(由MapsView.swift呈现)ScrollView中,策略显示如下:

struct MapsDetailView: View {

    var map: Map

    @ObservedObject private var viewModel = StratsViewModel()

    var body: some View {

        ScrollView {

            ForEach(viewModel.strats, id: \.self) { strat in

                    NavigationLink(destination: StratView()) {

                        StratCell(strat: strat)

                    }

            }

        }
        .onAppear() {

            self.viewModel.fetchData(forMap: map.id)
            
        }

    }

}

如果我要向视图添加一个按钮,例如,将任何值设置为 UserDefaults 中的任何键,ScrollView 中的几十个项目就会消失。

.toolbar {

    ToolbarItem(placement: .navigationBarTrailing) {

        Button {

            UserDefaults.standard.setValue("test", forKey: "testKey")

        } label: {

            Text("Don't press me!")

        }

    }

}

使用 TabBar 导航到另一个视图,然后返回到 MapDetailView 将触发 .onAppear 方法,但是,在上面显示的 ForEach 行添加一个断点,表明此循环不会't 运行 直到视图被完全关闭并重新打开。

在 TabBar 中切换选项卡时也会出现此问题,因为在 onAppear 时,每个视图都会设置一个 tabSelection 键,以记住应用程序被终止时用户最后选择的选项卡。从一个选项卡切换回 MapsDetailView 选项卡将删除 ScrollView 中的所有单元格。

有什么想法吗?如有必要,很乐意分享更多源代码。

当您初始化 viewModel 时,您应该使用 @StateObject 而不是 @ObservedObject。这两个 属性 包装器几乎相同,除了 @StateObject 将确保对象在更新/重新呈现视图时保持“活动”状态,而不是重新初始化。以下是有关此主题的一些重要资源:

What is @StateObject?

@ObservedObject vs @StateObject vs @EnvironmentObject