Firebase Swift - 当搜索控制器过滤结果时,实时更新不起作用

Posted

技术标签:

【中文标题】Firebase Swift - 当搜索控制器过滤结果时,实时更新不起作用【英文标题】:Firebase Swift - Realtime update does not work when result is filtered by search controller 【发布时间】:2018-04-23 13:22:08 【问题描述】:

我正在使用 Swift 和 Firebase 制作 ios 应用。视图控制器检索/观察项目并将它们存储在项目数组中。项目单元格具有 + 和 - 按钮,它们使用其 indexPath 执行项目数量的更新。

如果我使用搜索控制器过滤项目,我可以将搜索结果存储在 filtersItems 数组中。我正在尝试更新这些过滤项目的数量,但是当我点击 + 或 - 按钮时它们只会更新一次,并且不会在搜索结果视图中显示更新(没有单独的视图,我在同一视图中使用数据源显示过滤的项目)。即使我多次点击它,它也总是更新一次。

一旦我通过取消搜索栏返回常规视图,我看到 1 向上或向下取决于我点击的按钮。有谁知道这里的问题可能是什么原因?

class ItemsViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, SortTypeTableViewControllerDelegate, ItemListCellDelegate 
private var items = [Item]()
private var filteredItems = [Item]()

private func retrieveFirebaseData(sortType: ItemSort.SortType, sortOrder: ItemSort.SortOrder) 
guard let currentUser = Auth.auth().currentUser else 
  return print("user not logged in")


let itemsRef = DatabaseReferenceHelper.usersRef.child(currentUser.uid).child("items")

itemsRef.queryOrdered(byChild: sortType.rawValue).observe(.value)  (snapshot) in
  var newItems: [Item] = []

  for item in snapshot.children 
    let item = Item(snapshot: item as! DataSnapshot)
    if self.displayFavoritesOnly == true 
      if item.favorite == true 
        newItems.append(item)
      
     else 
      newItems.append(item)
    
  

  self.items = sortOrder == .ascending ? newItems : newItems.reversed()
  self.collectionView.reloadData()



// this is from item cell delegate
func increaseDecreaseQuantity(_ sender: ItemListCell, increment: Bool) 
  guard let tappedIndexPath = collectionView.indexPath(for: sender) else 
    return
  

  let item: Item
  item = isFiltering() ? filteredItems[tappedIndexPath.item] : items[tappedIndexPath.item]

  let updatedQuantity = increment == true ? item.quantity + 1 : item.quantity - 1

  guard let currentUser = Auth.auth().currentUser else 
    return print("user not logged in")
  

  let itemsRef = DatabaseReferenceHelper.usersRef.child(currentUser.uid).child("items")

  itemsRef.child(item.key).updateChildValues(["quantity": updatedQuantity])




// Here's the search logic I learned from Ray Wenderlich
private func searchBarIsEmpty() -> Bool 
  return searchController.searchBar.text?.isEmpty ?? true


private func filterContentForSearchText(_ searchText: String, scope: String = "All") 
  filteredItems = items.filter($0.title.lowercased().contains(searchText.lowercased()))
  collectionView.reloadData()


private func isFiltering() -> Bool 
  return searchController.isActive && !searchBarIsEmpty()



extension ItemsViewController: UISearchResultsUpdating 

  func updateSearchResults(for searchController: UISearchController) 
    filterContentForSearchText(searchController.searchBar.text!)
  

【问题讨论】:

使用此代码,每次更新特定项目时,都会重新加载整个项目列表。另一种选择是使用 .childAdded、.childChanged 和 .childRemoved,因此当仅修改一项时,您可以只更新数组中的一项。 @Jay 这是提高代码效率的建议还是可能的修复?我看到一篇博文说 .childAdded、.childChanged、.childRemoved 的具体用法可以保存数据,所以我也想使用它们。 这更像是一个建议,可以让它更干净一些,并减少对 Firebase 的命中和移动的数据量。我没有看到任何会导致您描述的问题的明显代码问题。 【参考方案1】:

在每个 + & - 之后重新加载您的 collectionView。重新加载集合视图后,将显示新的更新。

【讨论】:

我试过了,但它什么也没做。另外,当结果未被过滤时,我不需要重新加载集合视图来实时更新我的​​数据。【参考方案2】:

我解决了这个问题。我所做的只是在retrieveFirebaseData 函数中添加另一个名为“searchText”的参数,并在filterContentForSearchText 中使用该函数。

基本上,我需要像下面的代码一样在观察方法下过滤项目。

private func retrieveFirebaseData(sortType: ItemSort.SortType, sortOrder: ItemSort.SortOrder, searchText: String?) 

  guard let currentUser = Auth.auth().currentUser else 
    return print("user not logged in")
  


  let itemsRef = DatabaseReferenceHelper.usersRef.child(currentUser.uid).child("items")

  itemsRef.queryOrdered(byChild: sortType.rawValue).observe(.value)  (snapshot) in
    if let searchText = searchText 
      // FILTER HERE
      self.filteredItems = self.items.filter($0.title.lowercased().contains(searchText.lowercased()))
     else 
      var newItems: [Item] = []
      for item in snapshot.children 
        let item = Item(snapshot: item as! DataSnapshot)
        if self.displayFavoritesOnly == true 
          if item.favorite == true 
            newItems.append(item)
          
         else 
          newItems.append(item)
        
              
      self.items = sortOrder == .ascending ? newItems : newItems.reversed()
    

    self.collectionView.reloadData()
  


private func filterContentForSearchText(_ searchText: String, scope: String = "All") 
  retrieveFirebaseData(sortType: itemSortType, sortOrder: itemSortOrder, searchText: searchText)

“filterContentForSearchText”函数用于过滤项目并重新加载表格,如下所示:

private func filterContentForSearchText(_ searchText: String, scope: String = "All") 
  filteredItems = items.filter($0.title.lowercased().contains(searchText.lowercased()))
  collectionView.reloadData()

【讨论】:

以上是关于Firebase Swift - 当搜索控制器过滤结果时,实时更新不起作用的主要内容,如果未能解决你的问题,请参考以下文章

过滤和显示来自 firebase 数据库的搜索栏结果

使用 Swift 4 搜索自定义表格单元格和过滤器

Firebase - 为啥不搜索在我的应用中工作的用户? (当用户输入两个字母时更新搜索控制器)

Swift 中带有过滤器的高级 Firebase 查询

如何在swift ios中通过键值读取子数据或过滤firebase数据

过滤和排序 swift 数组