I’ve seen many similar questions posted, but none yet seemed to provide a solution to my version of the problem.
Simply put, a ForEach List view is not updating (or more accurately I suspect is updating too quickly) when the data in a published property is updated as a result of a get request to Firebase Firestore following the creation of new data in Firestore. I’m tearing my hair out as another near identical list, also connected to Firestore, works as desired – the only differnce I’m aware of being dependency injection of my database service functions.
Details:
Model
struct VenueCollection: Codable, Identifiable {
@DocumentID var id: String?
var name: String
var description: String?
var venues: [String: Date] // Where string is venue ID and Date is date added to collection
}
ViewModel
class AuthViewModel:NSObject, ObservableObject, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
@Published var collections: [VenueCollection] = []
func getUserCollections() {
guard let userID = Auth.auth().currentUser?.uid else { return }
databaseService.getUserCollections(userID: userID) { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success(let collections):
self?.collections = collections
case .failure(let error):
print("Error fetching collections: (error.localizedDescription)")
}
}
}
}
}
Database Service
func getUserCollections(userID: String, completion: @escaping (Result<[VenueCollection], Error>) -> Void){
let userPrivateCollectionsRef = Firestore.firestore().collection("users").document(userID).collection("private_collections")
userPrivateCollectionsRef.getDocuments { snapshot, error in
if let error = error {
print("Error fetching collections: (error.localizedDescription)")
completion(.failure(error))
return
}
let fetchedCollections: [VenueCollection] = snapshot?.documents.compactMap { document in
try? document.data(as: VenueCollection.self)
} ?? []
completion(.success(fetchedCollections))
}
}
View
struct CollectionsListView: View {
@EnvironmentObject var authViewModel: AuthViewModel
@Binding var showCreateCollection: Bool
var body: some View {
List {
ForEach (sortedCollections) { collection in
CollectionsRowView(venueCollection: collection)
.background(
NavigationLink("", destination: CollectionView(venueCollection: collection))
.opacity(0)
)
.listRowSeparator(.hidden)
}
Button {
showCreateCollection = true
} label: {
PrimaryButtonActiveToggle(isActive: true, ButtonText: "Create collection")
.padding(.horizontal)
}
.listRowSeparator(.hidden)
}
.listStyle(PlainListStyle())
.onAppear(){
authViewModel.getUserCollections()
}
}
When a collection is created, a function writes the collection to firebase. I then re-call the getUserCollections function(s) and dismsss the create collection view. Printing out data to the console shows that the count of collections is increased. But the list does not update until navigating away and back to the view, presumably triggering the onAppear getUserCollections, which this time, works.
I can’t figure out why, even though there is a delay in getting the data from Firebase, the list doesn’t update with the array does.
I’ve also tried optimistically updating the local array with the new venue, and that didn’t update the list either.
Hope I’ve shared enough/not too much code. Appreciate any help.