尝试搜索 Firestore 并重新加载 tableview 时出现 SearchBar 问题

Posted

技术标签:

【中文标题】尝试搜索 Firestore 并重新加载 tableview 时出现 SearchBar 问题【英文标题】:SearchBar problem while trying to search Firestore and reload the tableview 【发布时间】:2019-06-04 10:57:20 【问题描述】:

我有一个 tableView,我使用无限滚动来批量填充 firestore 数据。另外我有一个搜索栏,我正在尝试使用文本栏中的文本查询 firestore,然后将其填充到 tableview 中。我有 3 个主要问题。

    当我第一次单击搜索时,我得到一个空数组和一个空的 tableview,但是当我第二次单击搜索时,一切似乎都很好。

    当我最终填充搜索到的内容时,我希望在滚动时停止获取新内容。

    如果我输入了错误的单词并按了搜索,那么我会得到上一个搜索结果,然后“未找到任何成分”会打印两次。

这是我的 searchBar 代码:

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) 
        guard let text = searchBar.text else return
        searchIngredients(text: text)
        self.searchBarIngredient.endEditing(true)
        print("\(searchIngredients(text: text))")
    

点击搜索时的函数代码

func searchIngredients(text: String) -> Array<Any>

        let db = Firestore.firestore()

        db.collection("Ingredients").whereField("compName", arrayContains: text).getDocuments (querySnapshot, err) in
            if let err = err 
                print("\(err.localizedDescription)")
                print("Test Error")
             else 
                if (querySnapshot!.isEmpty == false)
                    self.searchedIngredientsArray = querySnapshot!.documents.compactMap(Ingredients(dictionary: $0.data()))

                else
                    print("No Ingredients found")
                
            
        

         self.tableView.reloadData()
         ingredientsArray = searchedIngredientsArray

        return ingredientsArray

    

最后是滚动代码

func scrollViewDidScroll(_ scrollView: UIScrollView) 

        let off = scrollView.contentOffset.y
        let off1 = scrollView.contentSize.height

        if off > off1 - scrollView.frame.height * leadingScreensForBatching
            if !fetchMoreIngredients && !reachEnd
                beginBatchFetch()
            
        
    

我不写 beginBatchFetch() 因为它工作正常,我认为不相关。 提前致谢。

【问题讨论】:

【参考方案1】:

您的问题是 Firestore 是 asynchronous。

Firestore 返回您请求的文档需要时间,并且该数据仅在调用该函数的闭包内有效。闭包外的代码将在闭包内的数据可用之前执行。

所以这就是发生的事情。

func searchIngredients(text: String) -> Array<Any>
    let db = Firestore.firestore()
    db.collection("Ingredients").whereField("compName", arrayContains: text).getDocuments (querySnapshot, err) in
        //the data has returned from firebase and is valid
    
    //the code below here will execute *before* the code in the above closure
    self.tableView.reloadData()
    ingredientsArray = searchedIngredientsArray
    return ingredientsArray

发生的事情是在数组中没有任何数据之前刷新 tableView。

您还可以在填充数组之前返回它。更重要的是,通常可以(并且应该)避免尝试从异步函数返回值。

解决方法是处理闭包内的数据

class ViewController: NSViewController 
   var ingredientArray = [String]()
   func searchIngredients(text: String) 
         let db = Firestore.firestore()
         db.collection("Ingredients").whereField("compName", arrayContains: text).getDocuments (querySnapshot, err) in
             //the data has returned from firebase and is valid
             //populate the class var array with data from firebase
             //    self.ingredientArray.append(some string)
             //refresh the tableview
         
     

请注意,searchIngredients 函数不应返回值 - 也不需要

【讨论】:

感谢您的回答。你让我明白了很多,它奏效了。现在的问题是它打印了两次“未找到成分”。 @NickStefanidis 好吧,有可能函数被调用了两次,或者 print 语句可能在循环中。该功能适用​​于我,只打印一次。也许用更新的代码和 Firestore 结构的 sn-p 询问另一个问题会有所帮助。 谢谢。这是我的错误。还有一件事。我有无限卷轴。当我拥有已建立的单元格时是否可以停止获取?会有超过 1 个,因为我有同义词。 @NickStefanidis 通常,如果您想要无限滚动,您将对数据进行分页,例如,您的应用程序一次加载 10 行,然后当用户滚动时,它将加载下一个 10等等。Paginating Data上的 Firestore 指南中有一些很棒的信息 我成功地对我的数据进行了分页,这不是问题。但是,当我搜索某些内容并使用已找到的数据重新加载 tableView 时,滚动后分页再次开始。无法禁用滚动,因为数据可能超过屏幕高度。

以上是关于尝试搜索 Firestore 并重新加载 tableview 时出现 SearchBar 问题的主要内容,如果未能解决你的问题,请参考以下文章

尝试将一组对象保存到 Firestore 并将其加载回来

如何在不重新加载页面的情况下更新从 firestore 检索到的标记在我的地图上?

表单自动仅提交一次并重新加载相同的页面

从 vue 更新 firestore,然后重新加载页面以获取更新的数据(不起作用)

Firestore - 节省文档读取费用

使用 Swift 搜索结果后,搜索栏没有重新加载到原始数据?