简体   繁体   English

在TableView中处理异步Firestore数据读取-iOS

[英]Handling asynchronous Firestore data reading in tableView - iOS

I would like to retrieve data from my simple Firestore database 我想从我的简单Firestore数据库中检索数据

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. 作为UI表示,我有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: 然后,numberOfRows为0,控制台中的输出为: 在此处输入图片说明

and I am ending up with no cells in tableView. 我最终在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"? 即使我有3个,它们还是有点“晚”? They are loaded afterwards. 它们随后被加载。 And then the tableView doesn't show anything but console says (later) that there are 3 cells. 然后,tableView不会显示任何内容,但是控制台会说(以后)有3个单元格。

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. 但是此方法甚至没有加载(控制台中没有打印),并且该方法写在具有numberOfRowsInSection的方法下面。

I have also 2 errors (I don't know why each line is written twice) and these are: 我也有2个错误(我不知道为什么每一行都写两次),它们是: 在此处输入图片说明

but I don't think it has something to do with the problem. 但我认为这与问题无关。

Thank you for your help! 谢谢您的帮助!

As @Galo Torres Sevilla mentioned, addSnapshotListener method is async and you need to add completion handler to your getDataFromDatabase() function. 如@Galo Torres Sevilla所述, addSnapshotListener方法是异步的,您需要将完成处理程序添加到getDataFromDatabase()函数中。

Make following changes in your code: 在代码中进行以下更改:

  1. Declare Global variable for notes. 为注释声明全局变量。

     var list_notes = [String]() 
  2. Add completion handler to getDataFromDatabase() method. 将完成处理程序添加到getDataFromDatabase()方法。

     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: 最后,在要获取便笺并将分配的便笺分配给全局变量并重新加载TableView适当位置调用函数,如下所示:

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

Changes in TableView: 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
}

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM