删除 SwiftUI 后 Firebase Firestore 不更新 UI

Posted

技术标签:

【中文标题】删除 SwiftUI 后 Firebase Firestore 不更新 UI【英文标题】:Firebase Firestore doesn't update UI after deletion SwiftUI 【发布时间】:2021-08-16 05:23:21 【问题描述】:

我正在尝试通过 SwiftUI 从我的 Firestore 数据库中删除一个对象,并且数据已成功删除。但是它不会在我的 UI 中更新,除非我手动重新加载它。

现在,我正在使用 @Environment(\.presentationMode) var presentation 在删除完成后关闭视图。

这是我的 Firebase 代码:

func deleteData(category: String,completion: @escaping (success) -> Void)
    db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").getDocument(snapshot, error) in
        guard let snapshot = snapshot, error == nil else 
            return
        
        let documentID = snapshot.data()!["date"] as! String
        db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID).document("\(category)").delete() err in
            if let err = err 
                print("Error removing document: \(err)")
                completion(false)
             else 
                print("Document successfully removed!")
                completion(true)
            
        
        
    

这是 SwiftUI 代码:

@Environment(\.presentationMode) var presentation
var body: some View 
    ForEach(self.data)item in
        HStack
            Text(item.category)
            Spacer()
            Button(action: 
                deleteData(category: item.category!)
                    (success) -> Void in
                    if success 
                        print("deleted successfully")
                        self.presentation.wrappedValue.dismiss()
                    
                
            )
                Text("Delete")
            
        
            .onAppear
                fetchData()
            
    





class FirebaseData: ObservableObject 
    @State var id: String?
    @State var category: String
    @State var password: String
    
    init(id: String?, password: String, category: String) 
        self.id = id
        self.password = password
        self.category = category
    

self.data 来自@State var data: [FirebaseData] = []

【问题讨论】:

除非显示相关代码,否则无法调试。 我的错,我编辑后忘记保存代码了,现在可以了:) 相关代码仍然没有。什么填充 self.data?它不会在 deleteData 中被操纵,因此它不会被更新是合理的。 data 是一个 Firebase 类,从 Firestore 中检索。是的,deleteData 从 Firestore 中删除了该特定数据,但它不会在 UI 上更新,除非我手动刷新它 您没有显示 self.data 的设置或操作位置,因此无法调试。 【参考方案1】:

这里有几个问题:

    一般来说,在进行异步工作时,您可能希望在ObservableObject 中进行,而不是在View 本身中进行——我已将代码移至视图模型中。

    你的模型不应该是ObservableObject——它应该只是一个结构。在ObservableObject 上使用@State 无论如何都不会做任何事情——使用ObservableObject 时使用@Published

    您正在使用 getDocument 获取数据一次,这就是您的 UI 没有更新的原因。如果您希望 UI 更新,请使用快照侦听器:https://firebase.google.com/docs/firestore/query-data/listen

struct FirebaseData 
    var id: String?
    var category: String
    var password: String


class ViewModel : ObservableObject 
    @Published var data : [FirebaseData] = []
    private let db = Firestore.firestore()
    private var listener : ListenerRegistration?
    
    func fetchData()
        db.collection("passwords").document("\(Auth.auth().currentUser!.uid)")
            .getDocument(snapshot, error) in
                guard let snapshot = snapshot, error == nil else 
                    return
                
                let documentID = snapshot.data()!["date"] as! String
                
                self.listener = self.db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID)
                    .addSnapshotListener() (querySnapshot, err) in //<-- Here
                        if let err = err 
                            print("Error getting documents: \(err)")
                         else 
                            self.data = (querySnapshot?.documents ?? []).map 
                                FirebaseData(id: $0.documentID,
                                             category: $0.data()["category"] as? String ?? "",
                                             password: $0.data()["password"] as? String ?? "")
                            
                        
                    
            
    
    
    func deleteData(category: String,completion: @escaping (success) -> Void)
        db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").getDocument(snapshot, error) in
            guard let snapshot = snapshot, error == nil else 
                return
            
            let documentID = snapshot.data()!["date"] as! String
            self.db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID).document("\(category)").delete() err in
                if let err = err 
                    print("Error removing document: \(err)")
                    completion(false)
                 else 
                    print("Document successfully removed!")
                    completion(true)
                
            
        
    


struct ContentView: View 
    
    @Environment(\.presentationMode) var presentation
    @StateObject private var viewModel = ViewModel()
    
    
    var body: some View 
        NavigationView
            ForEach(viewModel.data, id: \.self.id)  item in
                HStack
                    Text(item.category)
                    Spacer()
                    Button(action: 
                        viewModel.deleteData(category: item.category)
                            (success) -> Void in
                            if success 
                                print("deleted successfully")
                            
                        
                    )
                        Text("Delete")
                    
                
            
            .onAppear
                viewModel.fetchData()
            
        
    

我还要做一些重构,例如:

    确保您没有在任何地方使用 ! 来强制展开 - 这可能会导致崩溃 存储文档 ID,这样您就不会在 deleteData 中进行其他查询

但是,这应该让你现在就开始。

【讨论】:

太棒了!谢谢,你是一个救生员:)

以上是关于删除 SwiftUI 后 Firebase Firestore 不更新 UI的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 和 Firebase:如何删除用户?

无法使用 SwiftUI 从 Firebase / Firestore 中删除文档

SwiftUI Firebase。删除所有项目而不仅仅是一个

致命错误:索引超出范围,同时在 SwiftUI 的列表中从 Firebase 中删除项目

异步firebase调用后SwiftUI不更新变量

FireBase 登录过程后导航到主屏幕(内容视图)。 (SwiftUI)