【问题标题】:Desynchonization between realm collection notification and collection view count领域集合通知和集合视图计数之间的不同步
【发布时间】:2017-03-21 12:51:48
【问题描述】:

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

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

每次从 API 收到新项目时,我需要刷新集合视图中的 3 个部分。当我有 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 来避免崩溃,这会导致一些性能问题。我真的很想异步编写任何新项目,但我不知道它为什么会崩溃。请问有谁知道发生了什么以及如何改进?

【问题讨论】:

    标签: ios swift uicollectionview realm


    【解决方案1】:

    更新需要以与.update 案例中定义的顺序相同的顺序应用于您的collectionView:首先删除,其次插入,第三次修改。所以你的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) })
    })
    

    【讨论】:

    • 我试过你的答案。好像没关系,还是一样的问题
    【解决方案2】:

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    相关资源
    最近更新 更多