领域集合通知和集合视图计数之间的Desynchonization

时间:2017-03-21 12:51:48

标签: ios swift uicollectionview realm

我在我的项目中使用Realm来编写来自API的实时数据并同时填充UICollectionView。为了实现这一点,我一直在使用Realm的集合通知(https://realm.io/docs/swift/latest/#collection-notifications)来观察插入。我遇到的问题是,当我在集合视图中使用多个部分时,总是会出现以下错误:

  

由于未捕获的异常而终止应用   'NSInternalInconsistencyException',原因:'无效更新:无效   第2节中的项目数。包含在项目中的项目数   更新后的现有部分(4)必须等于数量   更新前的该部分中包含的项目(3),加号或减号   从该部分插入或删除的项目数(0已插入,   0已删除)并加上或减去移入或移出的项目数   该部分(0移入,0移出)。'

我在集合视图中有3个部分,每次从API接收新项目时都需要刷新。当我有1个部分时它完美地工作但是当我有3个部分时会导致崩溃。为此,我有一个NotificationToken数组,我会观察到新的插入:

 internal func observeResults(results: Results<SJResult>, section: Int) {
      notificationTokens.append(results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
        switch changes {
          case .initial:
            collectionView.reloadData()
            break
          case .update(_, let deletions, let insertions, let modifications):
            collectionView.performBatchUpdates({
              collectionView.insertItems(at: insertions.map { IndexPath(row: $0, section: section) })
              collectionView.deleteItems(at: deletions.map { IndexPath(row: $0, section: section) })
              collectionView.reloadItems(at: modifications.map { IndexPath(row: $0, section: section) })
            })
            break
          case .error(let error):
            fatalError("\(error)")
            break
        }
      })
    }

我将结果写在后台队列中:

DispatchQueue.global(qos: .background).async { [weak self] in
  for (index, group) in groups.enumerated() {
    let result = Item(group: group)

    if let realm = try? Realm() {
      do {
        try realm.write {
          realm.add(result)
        }
      } catch let exception {
        print("Can't write result: \(exception)")
      }
    }
  }
}

这就是我如何指定每个部分中的项目数量:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return results(leg: section).count // Query the table to get the results I want to display
}

似乎当集合视图插入新元素(在collectionView.performBatchUpdates中)时,有时会在数据库realm.add(result)上同时写入新项目,这会导致崩溃更新的开始和结束之间的项目总数已更改。我设法通过同步写DispatchQueue.global(qos: .background).sync来避免崩溃,这会导致一些性能问题。我真的想异步写任何新项目,但我无法弄清楚它崩溃的原因。有没有人知道发生了什么以及如何改善它?

2 个答案:

答案 0 :(得分:2)

更新需要以与collectionView案例中定义的顺序相同的顺序应用于.update:首先删除,第二次删除,第三次修改。因此,您的performBatchUpdates块应如下所示:

collectionView.performBatchUpdates({
  collectionView.deleteItems(at: deletions.map { IndexPath(row: $0, section: section) })
  collectionView.insertItems(at: insertions.map { IndexPath(row: $0, section: section) })
  collectionView.reloadItems(at: modifications.map { IndexPath(row: $0, section: section) })
})

答案 1 :(得分:1)

我现在正在努力解决同样的问题。我的最新理论解释了为什么它与一个部分完美配合并开始崩溃多个部分如下: 集合视图检查动画开头部分中的项目数,并在结束时再次检查一致性错误。只要您有一个部分,对结果的更改将生成一系列通知,每个通知都会启动一个新的performBatchUpdates,它将使所有内容完全同步。 如果您有多个部分,并且自己的通知附加到不同的结果,则会开始交错的通知序列,这些通知会启动自己的performBatchUpdates,更重要的是检查每个动画结束时所有部分的计数。 这可能是你和我遇到这些问题的原因。我们每个部分都有单独的通知,但他们的工作会影响整个收集视图部分,包括之前开始的飞行动画和飞行结束检查。我还没有解决这个问题的方法。