如何处理 'Assertion Failure' Collectionview 在 Swift 的 Firebase 数据库中崩溃?

How to deal with 'Assertion Failure' Collection View crashes in Firebase DatabaseUI in Swift?

我正在我的应用程序上构建一个屏幕,其中的配置文件将显示在集合视图中。正在从 Firebase 检索我的数据,这是我第一次使用 Firebase DatabaseUI。

我正在构建一个查询,然后创建一个 FUICollectionViewDataSource,使我的单元格出列,然后将该数据源插入到 collectionView 中。

只要我在在线用户和离线用户之间切换(检查查询中子键的值),数据源的功能就可以正常工作,但是当我将查询从男性更改为女性时,或女性对男性,(一个新的查询本身)我崩溃了NSInternalInconsistenencyException

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (1) must be equal to the number of items contained in that section before the update (1), plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'

*** First throw call stack: (0x18672d1b8 0x18516455c 0x18672d08c 0x1871e502c 0x18cedc14c 0x18c7b1d4c 0x10020f594 0x1002102c8 0x1001eb3e0 0x101609258 0x101609218 0x10160e280 0x1866da810 0x1866d83fc 0x1866062b8 0x1880ba198 0x18c64d7fc 0x18c648534 0x1000c4200 0x1855e95b8) libc++abi.dylib: terminating with uncaught exception of type NSException

当我构建集合视图时,我习惯于 运行ning 像这样的命令:

collectionView.dataSource = collectionViewDataSource
self.collectionView.reloadData()

但现在上面的调用不起作用,而且我没有使用 UICollectionViewDataSource 协议函数,我不确定如何创建、运行ning 和显示新的每个部分总是有不同数量的项目的查询。

在处理新查询之前,我必须 运行 执行哪些功能才能避免此类崩溃?

我试过从 collectionView 的 indexPathsForVisibleItems 中删除所有单元格,然后重新加载数据...我到处乱扔 collectionView.reloadData(),但仍然崩溃。不是所有时候,但应用程序迟早会崩溃。

如何在 collectionView 上开始一个全新的查询而不必处理 NSInternalInconsistencyExceptions

谢谢大家。我喜欢 Firebase,很想弄明白!

-瑞兹

当 VC 加载时,调用 getUserData() 函数。 当查询更改时,resetQuery() 函数是来自已发布通知的 运行。

extension BrowseVC {
  func getUserData() {
    let isOnline = (segmentedControl.selectedSegmentIndex == 0) ? true : false
    generateQuery(isOnline: isOnline)
    populateDataSource()
  }

  func resetQuery() {
    removeOldData()
    getUserData()
  }

  func removeOldData() {
    let indexPaths = collectionView.indexPathsForVisibleItems
    collectionView.deleteItems(at: indexPaths)
//    collectionView.reloadData()
  }

  func generateQuery(isOnline: Bool) {
    if let selectedShowMe = UserDefaults.sharedInstance.string(forKey: Constants.ProfileKeys.ShowMe) {
      let forMen = (selectedShowMe == Constants.ProfileValues.Men) ? true : false
      query = FirebaseDB.sharedInstance.buildQuery(forMen: forMen, isOnline: isOnline)
    } else {
      query = FirebaseDB.sharedInstance.buildQuery(forMen: false, isOnline: isOnline)
    }
  }

  func populateDataSource() {
    if let query = query {
      collectionViewDataSource = FUICollectionViewDataSource(query: query, view: collectionView, populateCell: { (view, indexPath, snapshot) -> ProfileCVCell in
        if let cell = view.dequeueReusableCell(withReuseIdentifier: Constants.CollectionViewCellIdentifiers.ProfileCVCell, for: indexPath) as? ProfileCVCell {
          if let userDictionary = snapshot.value as? [String: AnyObject] {
            if let user = User(uid: snapshot.key, userDictionary: userDictionary) {
              cell.populate(withUser: user)
            }
          }

          return cell
        }
        return ProfileCVCell()
      })

      collectionView.dataSource = collectionViewDataSource
      collectionView.reloadData()
//      collectionView.performBatchUpdates({
//        self.collectionView.dataSource = self.collectionViewDataSource
//      }, completion: nil)
//      collectionView.reloadData()
    }
  }
}

您 运行 参与其中的原因是 FirebaseUI 数据库数据源负责将更新推送到集合视图本身。这样您就可以免费获得动画更新,并且永远不必调用 reloadData。

当您将旧数据源换成新数据源时,您需要将数据源的集合视图设置为 nil,以便停止将事件推送到集合视图。