In my app, I have a place to show news, located in one of the 4 tab views. For changing the information, all the aspects related to it are stored in firestore (title, subtitle, text). Currently, I'm using addSnapshotListener to fetch the data, because whenever I change the data in firestore it will automatically and instantly update. However, each time the user clicks on the tabview icon related to the news view, a different call to read data is done. I understand that it would cause lots of readings when the user base grow, causing a higher monthly payment to firebase and maybe delay, right? To fix this, the only solution I think about is changing addSnapshotListener to getDocuments. But, if I do any changes on firestore, the user would need to close the app and then open it to see the updated info. Is there a way to update instantly the info, but only if changes are made in the database?
This is how I get the information from Firestore:
struct Info: Identifiable{ var id: String = UUID().uuidString var title: String var subtitle: String } class InfoViewModel: NSObject, ObservableObject { @Published var infos = [Info]() func fetchData(){ Firestore.firestore().collection("infos").addSnapshotListener { (querySnapshot, error) in guard let documents = querySnapshot?.documents else {return} self.infos = documents.compactMap { (queryDocumentSnapshot) -> Info? in let data = queryDocumentSnapshot.data() if let title = data["title"] as? String, let subtitle = data["subtitle"] as? String{ print("info successful") return Info(title: title, subtitle: subtitle) } else{ print("info failed") return nil } } } } } In the view I want to display the info, I have @ObservedObject var infoModel = InfoViewModel(), a ForEach to display the data and then .onAppear(){self.infoModel.fetchData()}
Each time I change to this view when clicking the tabView icon, I get, on debug, 3x "info successful, as I have 3 documents stored on infos collection.
TabBar View:
struct TabBar: View{ @State var current = 0 @StateObject var LocationModel = LocationViewModel() var body: some View{ NavigationView{ TabView(selection: $current) { HomeView() .tag(0) .tabItem { Image(systemName: "house") Text("início") } SearchView(LocationModel: LocationModel) .tag(1) .tabItem { Image(systemName: "magnifyingglass") Text("buscar") } CalendarView() .tag(2) .tabItem { Image(systemName: "calendar") Text("histórico") } AccountView() .tag(3) .tabItem { Image(systemName: (self.current == 3 ? "person.fill" : "person")) Text("perfil") } }.accentColor(Color("Color")) } } } Where firestorm data is displayed:
struct HomeView: View{ @StateObject var LocationModel = LocationViewModel() @StateObject var model = ModelData() @ObservedObject var infoModel = InfoViewModel() var body: some View{ VStack( spacing: 12) { ScrollView(.vertical, showsIndicators: false){ ScrollView(.horizontal, showsIndicators: false){ HStack(spacing: 15){ ForEach(infoModel.infos){ info in HStack(spacing: 20){ Text(info.title) .frame(height: 220) .frame(width: 330) .background(Color.yellow) .cornerRadius(18) } } }.padding(.horizontal, 15) .padding(.bottom, 25) } } .navigationBarTitle("").navigationBarHidden(true) }.navigationBarTitle("").navigationBarHidden(true) .onAppear(perform: { LocationModel.locationManager.delegate = LocationModel self.infoModel.fetchData() }) .alert(isPresented: $LocationModel.alert, content: { Alert(title: Text("Mensagem"), message: Text(LocationModel.alertMsg), dismissButton: .destructive(Text("Pronto").foregroundColor(Color.blue))) }) } }
addSnapshotListenerand preserve data for VC to displaya different call to read data is done- we don't know what 'a different call' is or does. We also don't know if there's an issue with other code as well. Please take a moment and review How do I ask a good question? and How to create a Minimal, Complete, and Verifiable example. The Question is also unclear so maybe you can clarify it?