如何解决此 CollectionView 崩溃?

Posted

技术标签:

【中文标题】如何解决此 CollectionView 崩溃?【英文标题】:How to solve this CollectionView crash? 【发布时间】:2016-03-31 12:59:15 【问题描述】:

我的应用有两个CollectionViewControllers。在给定时间只有一个可见。

我在情节提要上创建了以下结构:两个容器视图相互叠加。每个容器视图都嵌入了CollectionViewController。特定容器视图的可见性决定了哪个 collectionViewController 可见。

这就是问题所在。两个CollectionViewControllers 都在并行接收数据,但ios 有一个错误,如果一个CollectionViewController 尝试在不可见的情况下使用performBatchUpdates 执行插入,则会导致应用程序崩溃。

为了防止这种情况,我在CollectionViewControllers 上都创建了一个 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 设置为YESperformBatchUpdates 使应用程序崩溃并出现此错误:

* -[CollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:] 中的断言失败,/BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.7/UICollectionView.m:4625 * 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效更新:无效 第 0 节中的项目数。包含在第 0 节中的项目数 更新后的现有节(76)必须等于 更新前该部分中包含的项目 (70),加号或减号 从该部分插入或删除的项目数(插入 5 个, 2 已删除)和加减移入或移出的项目数 该部分(0 移入,0 移出)。'

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

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

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

【问题讨论】:

您提到iOS 有一个与performBatchUpdates 相关的错误。你是怎么确定的?您确定问题不在于您的代码吗?使用标志来检查可见/不可见似乎可能不可靠。 我发现了一堆与 performBatchUpdates 错误相关的雷达条目,但无论如何,在这种情况下,我不再使用该标志。那只是想看看问题出在哪里。 【参考方案1】:

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

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

【讨论】:

你能指定在哪里插入这条神奇的线吗?我在实际更新之前尝试过,但没有任何影响 尝试控制器WillChangeContent 但您需要在批量更新调用之前调用魔法线。在这里查看:devforums.apple.com/message/908659#908659 此问题还会影响在项目不可见时移除项目。 即使现在仍然是解决方案【参考方案2】:

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

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

如苹果文档中所写

在批处理操作中,在插入之前处理删除。这表示 删除的索引是相对于 批处理操作之前集合视图的状态,以及 插入的索引相对于 批处理操作中所有删除后的状态。

所以,在插入之前移动更改,这样就可以了!

【讨论】:

不幸的是,据我验证一百次,我正在更新数据源,这很奇怪。 在批量操作中插入之前处理删除。这意味着删除的索引是相对于批处理操作之前的集合视图状态的索引来处理的,而插入的索引是相对于批处理操作中所有删除之后的状态的索引来处理的。 所以在插入你的 performBatchUpdate 块之前一定要删除 现在就这样做了。仍然崩溃。 performBatchUpdates 内部,我按顺序执行插入、删除和更改。你告诉我在插入之前先删除。我这样做了,它继续崩溃,但后来我在插入之前移动了更改,它就成功了。现在它没有崩溃。请将此更新添加到您的答案中,以便我接受。谢谢!!!!!!【参考方案3】:

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

  NSArray *selectedItemsIndexPaths = [self.collectionView indexPathsForSelectedItems];

用这个:

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

自己维护索引,现在可以了。如果您已更新数据源,则该错误不应与数据源相关联。这可能与细胞的重复使用有关。

【讨论】:

以上是关于如何解决此 CollectionView 崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

CollectionView.ReloadItemsForIndexPaths 迅速崩溃

自定义 CollectionView 崩溃 iOS

如何在 CollectionView 单元内向图像添加渐变层

频繁重新加载collectionView时崩溃

CollectionView + UIKit Dynamics 在 performBatchUpdates 上崩溃:

尝试隐藏页脚/页眉时,collectionView.performBatchUpdates 崩溃