如何解决此 CollectionView 崩溃?

How to solve this CollectionView crash?

我的应用有两个 CollectionViewController。在给定时间只能看到一个。

我在故事板上创建了以下结构:两个容器视图相互重叠。每个容器视图都嵌入了 CollectionViewController。特定容器视图的可见性决定了哪个 collectionViewController 可见。

这就是问题所在。两个 CollectionViewController 都在并行接收数据,但是 iOS 有一个错误,如果一个 CollectionViewController 试图在它不可见时使用 performBatchUpdates 执行插入,该错误会使应用程序崩溃。

为了防止这种情况发生,我在两个 CollectionViewController 上都创建了一个 BOOL 标志,这样它们就可以知道它们是否可见并执行或不执行 performBatchUpdates。类似于:

if (self.isThisCollectionViewVisible == NO) return;

[self.collectionView performBatchUpdates:^{
   // bla bla... perform insert,m remove...

这解决了部分问题。但是应用程序在以下情况下继续崩溃:如果我点击按钮切换到不可见 CollectionViewController 使其在接收更新时可见。

我的意思是:让我们调用 A 第一个 CollectionViewControllerB 第二个。此时 A 可见,B 不可见。 B 开始接收数据并尝试执行 performBatchUpdates 但由于它是不可见的,因此 if (self.isThisCollectionViewVisible == NO) return; 正在阻止 performBatchUpdates 到 运行,这很好。现在我让 A 不可见,B 可见。此时标志 self.isThisCollectionViewVisible 设置为 YES 并且 performBatchUpdates 使应用程序崩溃并出现此错误:

* Assertion failure in -[CollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.7/UICollectionView.m:4625 * 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 (76) must be equal to the number of items contained in that section before the update (70), plus or minus the number of items inserted or deleted from that section (5 inserted, 2 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'

我认为 CollectionViewController 确实还没有准备好并进行更新以能够执行 performBatchUpdates... 这不是之前不更新数据源的问题,因为它是正在更新。

我可以做什么检查来防止这种情况发生?

注意:我特别注意到这次崩溃有些奇怪。它说插入了 5 个元素,删除了 2 个元素,但实际上在发生崩溃时插入了 3 个元素,删除了 0 个元素,更改了 2 个元素。

这次崩溃告诉您您没有为收集更新数据源。您需要更新数据源(数组或字典)并在执行 performBatchUpdates 后重新加载集合视图数据。

无效更新:部分 0 中的项目数无效。更新后现有部分中包含的项目数 (76) 必须等于更新前该部分中包含的项目数 (70),加上或减去从该部分插入或删除的项目数(插入 5 个,删除 2 个),加上或减去移入或移出该部分的项目数(移入 0 个,移出 0 个)。'

如苹果文档中所写

Deletes are processed before inserts in batch operations. This means the indexes for the deletions are processed relative to the indexes of the collection view’s state before the batch operation, and the indexes for the insertions are processed relative to the indexes of the state after all the deletions in the batch operation.

所以,将更改移到插入之前,它会成功的!

对我来说,添加 self.collectionView.numberOfItemsInSection(0) 修复了崩溃。 collectionView 在不可见时插入项目时出现问题。

看来我的解决方案并不孤单:http://www.openradar.me/15262692

今天遇到同样的错误,对我来说,在 performBatchUpdates 块中替换为:

  NSArray *selectedItemsIndexPaths = [self.collectionView indexPathsForSelectedItems];

有了这个:

  NSIndexPath *selectedIndexPath = [NSIndexPath indexPathForRow:self.selectIndex inSection:0];
  NSArray *selectedItemsIndexPaths = @[selectedIndexPath];

自己维护索引,现在可以了。如果您更新了数据源,则该错误不应与数据源相关联。可能跟cell的再利用有关。