Handling asynchronous Firestore data reading in tableView - iOS

这一生的挚爱 提交于 2021-01-01 10:12:57

问题


I would like to retrieve data from my simple Firestore database

I have this database:

then I have a model class where I have a method responsible for retrieving a data which looks like this:

func getDataFromDatabase() -> [String] {
    var notes: [String] = []
    collectionRef = Firestore.firestore().collection("Notes")

    collectionRef.addSnapshotListener { querySnapshot, error in
            guard let documents = querySnapshot?.documents else {
                print("Error fetching documents: \(error!)")
                return
            }
        notes = documents.map { $0["text"]! } as! [String] // text is a field saved in document
            print("inside notes: \(notes)")
    }
    print("outside notes: \(notes)")
    return notes
}

and as a UI representation I have tableViewController. Let's take one of the methods, for example

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print("tableview numberOfRowsInSection called")
    return model.getDataFromDatabase().count
}

Then numberOfRows is 0 and the output in the console is:

and I am ending up with no cells in tableView. I added a breakpoint and it doesn't jump inside the listener.

And even though I have 3 of them, they are kinda "late"? They are loaded afterwards. And then the tableView doesn't show anything but console says (later) that there are 3 cells.

If needed, there is also my method for showing the cells names:

 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    print("Cells")
    let cell = tableView.dequeueReusableCell(withIdentifier: "firstCell", for: indexPath)

    cell.textLabel!.text = String(model.getDataFromDatabase()[indexPath.row].prefix(30))

    return cell
}

but this method is not even loaded (no print in the console) and this method is written below the method with numberOfRowsInSection.

I have also 2 errors (I don't know why each line is written twice) and these are:

but I don't think it has something to do with the problem.

Thank you for your help!


回答1:


As @Galo Torres Sevilla mentioned, addSnapshotListener method is async and you need to add completion handler to your getDataFromDatabase() function.

Make following changes in your code:

  1. Declare Global variable for notes.

    var list_notes = [String]()
    
  2. Add completion handler to getDataFromDatabase() method.

    func getDataFromDatabase(callback: @escaping([String]) -> Void) {
        var notes: [String] = []
        collectionRef = Firestore.firestore().collection("Notes")
    
        collectionRef.addSnapshotListener { querySnapshot, error in
            guard let documents = querySnapshot?.documents else {
                print("Error fetching documents: \(error!)")
                return
            }
            notes = documents.map { $0["text"]! } as! [String] // text is a field saved in document
            print("inside notes: \(notes)")
    
            callback(notes)
        }
    }
    
  3. Lastly, call function on appropriate location where you want to fetch notes and assign retrieved notes to your global variable and reload TableView like below:

    self.getDataFromDatabase { (list_notes) in
        self.list_notes = list_notes
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
    

Changes in TableView:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print("tableview numberOfRowsInSection called")
    return self.list_notes.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    print("Cells")
    let cell = tableView.dequeueReusableCell(withIdentifier: "firstCell", for: indexPath)

    cell.textLabel!.text = String(self.list_notes[indexPath.row].prefix(30))

    return cell
}



回答2:


All you need to do is refresh the table cell every time you retrieve the data. Put this code after you set your data inside the array.

self.tableView.reloadData()


来源:https://stackoverflow.com/questions/55504778/handling-asynchronous-firestore-data-reading-in-tableview-ios

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!