Here is the scenario: Onappear my view calls the getData method of my ObservableObject Class. During debug I see that it retrieves the data and returns the array as expected. When my view appears on the simulator the data flashes briefly on the list, then the list goes blank. I use this same pattern in several places in my application and in some cases it works (the list appears as it should) and in others it goes blank.
I'm testing on both 13.0 and 13.3 simulators due to various swiftUI bugs that work on one or the other. I thought it may be because of the async call to Firestore, but I've implemented completion handlers. IF I change the ObservedObject to a @State then the list appears correctly, but when new items are added it doesn't refresh.
Here is code for one of the examples that is not working:
My VIEW:
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))
}
}
My Observable Class:
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)
}
}
}
For my lists that are working, I am using basically the exact same code except changing the Firestore documents, data elements, variable names, etc.. They even run the same way in the debugger, only difference is some work and display the list and others don't.