SwiftUI列表会闪烁我的数据,然后使用ObservableObject获取Firestore数据显示一个空列表

时间:2020-03-21 01:51:48

标签: google-cloud-firestore swiftui swiftui-list

这是场景:在我的视图上,我的视图调用了ObservableObject类的getData方法。在调试过程中,我看到它检索数据并按预期返回数组。当我的视图出现在模拟器上时,数据在列表上短暂闪烁,然后列表变为空白。我在应用程序中的多个地方都使用了相同的模式,在某些情况下它可以工作(列表按预期显示),而在其他情况下则为空白。

由于各种swiftUI错误可在一个或另一个上运行,因此我正在13.0和13.3模拟器上进行测试。我认为可能是由于对Firestore的异步调用,但是我实现了完成处理程序。如果我将ObservedObject更改为@State,则该列表会正确显示,但是添加新项目时不会刷新。

以下是其中一个无效示例的代码:

我的观点:

import SwiftUI
import Firebase 

struct ManagerListView: View {
    var circuitId: String
    @State private var isMgr:Bool = true //TODO: reset to false
    @EnvironmentObject var session : SessionStore
    @ObservedObject var managerArray = ManagerList()


    func deleteMgrDb(manager: Manager) {
        let docRef = Firestore.firestore().collection("circuits").document(circuitId).collection("managers").document(manager.id)

        docRef.delete { (error) in
            if error != nil {
                print(error!.localizedDescription)
            }
        }
    }
     var body: some View {
        List {
            ForEach(managerArray.managers) { i in

                Text("\(i.firstName) \(i.lastName)  \(i.phone)").deleteDisabled(!self.isMgr)
            }.onDelete { (indexset) in
                let manager = self.managerArray.managers[indexset.first!]
                print("Here \(self.managerArray.managers[indexset.first!])")
                //TODO:  Check if owner (can't remove owner) or maybe if at least one manager (then delete owner?)
                self.managerArray.managers.remove(atOffsets: indexset)
                self.deleteMgrDb(manager: manager)
            }.disabled(!isMgr)

        }.onAppear(perform: {
            self.managerArray.getData(forcircuitid: self.circuitId) { (error) in
                if error != nil {
                    //TODO: Return data error to user
                    print(error!.localizedDescription)
                }
                //TODO: isMgr
            }
        }).onDisappear(perform: {
             self.managerArray.stopMgrListListener()
        }).navigationBarItems(trailing: isMgr ?
            NavigationLink(destination: CircuitManagerAddView(circuitId: self.circuitId, currentmgrs: managerArray.managers), label: {
                Image(systemName: "plus")
            }): nil) //.disabled(!isMgr))
     }
}

我的可观察班:

class ManagerList: ObservableObject {
    @Published var managers = [Manager]()

    var listener: ListenerRegistration?

    func getData(forcircuitid: String, completion: @escaping (Error?)->Void) {

        let db = Firestore.firestore().collection("circuits").document(forcircuitid).collection("managers")

        self.managers.removeAll()

        listener = db.addSnapshotListener { (snapshot, error) in
            if error != nil {
                print(error!.localizedDescription)
                completion(error)
            }
            else {
                for i in snapshot!.documentChanges {
                    if i.type == .added {
                        let email  = i.document.get("email") as! String
                        let lastName = i.document.get("lastname") as! String
                        let firstName = i.document.get("firstname") as! String
                        let phone = i.document.get("phonenum") as! String

                        let manager = Manager(id: email, lastName: lastName, firstName: firstName, phone: phone)

                        self.managers.append(manager)

                        //TODO:  Changed
                    }
                }
                completion(nil)
            }
        }
    }

对于正在运行的列表,除更改Firestore文档,数据元素,变量名称等外,我基本上使用完全相同的代码。它们甚至在调试器中以相同的方式运行,唯一的区别是工作和显示该列表,其他则没有。

1 个答案:

答案 0 :(得分:0)

列表项消失了,因为每次ManagerListView数据更改时,ManagerList都会重新初始化。发生这种情况时,ManagerList也将重新初始化,但是您在onAppear中执行的代码只会在第一次出现视图时调用,而不会在随后的数据更改时调用。

SwiftUI不保证@ObservedObject变量的生命周期。您必须自己进行管理。他们在iOS 14中引入了@StateObject,以简化此过程。您可以阅读更多here

请注意,onDisappear仅在不再显示视图时调用。最好从类反初始化函数中删除ManagerList中的Firebase侦听器。