Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在tableView-iOS中处理异步Firestore数据读取_Ios_Swift_Firebase_Google Cloud Firestore - Fatal编程技术网

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

在tableView-iOS中处理异步Firestore数据读取,ios,swift,firebase,google-cloud-firestore,Ios,Swift,Firebase,Google Cloud Firestore,我想从我的简单Firestore数据库中检索数据 我有这个数据库: 然后我有一个模型类,其中有一个方法负责检索数据,如下所示: func getDataFromDatabase() -> [String] { var notes: [String] = [] collectionRef = Firestore.firestore().collection("Notes") collectionRef.addSnapshotListener { querySnap

我想从我的简单Firestore数据库中检索数据

我有这个数据库:

然后我有一个模型类,其中有一个方法负责检索数据,如下所示:

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
}
作为UI表示,我有tableViewController。让我们以其中一种方法为例

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print("tableview numberOfRowsInSection called")
    return model.getDataFromDatabase().count
}
然后numberOfRows为0,控制台中的输出为:

我在tableView中没有单元格。我添加了一个断点,它不会在侦听器中跳转

即使我有三个,他们还是有点“迟到”?然后再装。然后tableView没有显示任何内容,只是控制台(稍后)说有3个单元格

如果需要,还有我显示单元格名称的方法:

 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
}
但是这个方法甚至没有加载(控制台中没有打印),并且这个方法写在带有numberOfRowsInSection的方法下面

我还有两个错误(我不知道为什么每行写两次),它们是:

但我认为这与问题无关


谢谢你的帮助

每次检索数据时,只需刷新表单元格即可。在数组中设置数据后,请输入此代码

self.tableView.reloadData()

您只需在每次检索数据时刷新表单元格。在数组中设置数据后,请输入此代码

self.tableView.reloadData()

正如@Galo Torres Sevilla提到的,
addSnapshotListener
方法是异步的,您需要将完成处理程序添加到
getDataFromDatabase()
函数中

在代码中进行以下更改:

  • 声明notes的全局变量

    var list_notes = [String]()
    
  • 将完成处理程序添加到
    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)
        }
    }
    
  • 最后,在要获取注释的适当位置调用函数,并将检索到的注释分配给全局变量,然后重新加载
    TableView
    ,如下所示:

    self.getDataFromDatabase { (list_notes) in
        self.list_notes = list_notes
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
    
  • 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
    }
    

    正如@Galo Torres Sevilla提到的,
    addSnapshotListener
    方法是异步的,您需要将完成处理程序添加到
    getDataFromDatabase()
    函数中

    在代码中进行以下更改:

  • 声明notes的全局变量

    var list_notes = [String]()
    
  • 将完成处理程序添加到
    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)
        }
    }
    
  • 最后,在要获取注释的适当位置调用函数,并将检索到的注释分配给全局变量,然后重新加载
    TableView
    ,如下所示:

    self.getDataFromDatabase { (list_notes) in
        self.list_notes = list_notes
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
    
  • 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
    }
    

    Firestore是异步的,因此notes在从服务器下载数据之前以空数组的形式返回。填充viewController变量并添加一个didSet观察者,或者将completionHandler添加到
    getDataFromDatabase
    method@GaloTorresSevilla请您提供代码解决方案好吗?至少是一些较小的,因为这是我第一次实现它。我理解你的评论,但我无法实施。谢谢。@MapeSVK我刚刚发布了一个解决方案。希望有帮助@MapeSVK实际上手头没有电脑。这就是为什么我没有发布答案。但是@Bhumik的answerFirestore是异步的,所以notes在从服务器下载数据之前以空数组的形式返回。填充viewController变量并添加一个didSet观察者,或者将completionHandler添加到
    getDataFromDatabase
    method@GaloTorresSevilla请您提供代码解决方案好吗?至少是一些较小的,因为这是我第一次实现它。我理解你的评论,但我无法实施。谢谢。@MapeSVK我刚刚发布了一个解决方案。希望有帮助@MapeSVK实际上手头没有电脑。这就是为什么我没有发布答案。但是你已经有了一个很好的@Bhumik的答案谢谢你,伙计,这很有效!只有一个问题。为什么这么复杂?这不是最基本的东西吗?也许我做得不对,对吧?很高兴这有帮助!代码的唯一问题是,您并没有等待Firestore下载数据。因此,
    cellForRowAt:indepath:
    方法在下载完成之前执行。通过添加完成处理程序,它解决了这个问题。谢谢你,伙计,它工作了!只有一个问题。为什么这么复杂?这不是最基本的东西吗?也许我做得不对,对吧?很高兴这有帮助!代码的唯一问题是,您并没有等待Firestore下载数据。因此,
    cellForRowAt:indepath:
    方法在下载完成之前执行。通过添加完成处理程序,它解决了这个问题。