SwiftUI UserDefaults 干扰 Firebase Firestore 数据

Posted

技术标签:

【中文标题】SwiftUI UserDefaults 干扰 Firebase Firestore 数据【英文标题】:SwiftUI UserDefaults interfering with Firebase Firestore data 【发布时间】:2021-02-18 19:20:35 【问题描述】:

我正在使用 Google Firebase 的 Cloud Firestore 服务和一个 SwiftUI 项目,该项目基于每个地图详细说明视频游戏中的策略。我正在使用视图、视图模型、模型架构。值得注意的是,我使用 Swift 包管理器来导入 API,而不是 CocoaPods。

我有一个 ScrollView,其中包含从 Firestore 集合中获取的一些地图。点击地图将向用户展示另一个 ScrollView,其中列出了从 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 行中添加一个断点,表明此循环不会再次运行,直到视图完全关闭并重新打开。

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

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

【问题讨论】:

也许 viewModel 正在重新初始化但 .fetchData 没有被调用?尝试将@ObservedObject 更改为@StateObject。 【参考方案1】:

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

What is @StateObject?

@ObservedObject vs @StateObject vs @EnvironmentObject

【讨论】:

以上是关于SwiftUI UserDefaults 干扰 Firebase Firestore 数据的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:如何使用 UserDefaults 保存选择器数据?

如何在 SwiftUI 中将 Stepper 数据保存到 UserDefaults?

SwiftUI 从 UserDefaults.standard 存储和提取字典

在 SwiftUI 中使用 UserDefaults 进行全局更新

当 UserDefaults 值更改 SwiftUI 时,@FetchRequest 谓词不会更新

UserDefaults 在 SwiftUI 中与 Toggle 绑定