什么导致这个iOS崩溃? UICollectionView收到一个索引path不存在的单元格的布局属性

我正在开发一个应用程序,它有一个UICollectionViewController,在某些难以复制的神秘情况下崩溃。 崩溃的日志如下所示:

*** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit_Sim/UIKit-3318.16.14/UICollectionViewData.m:417 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0xc000000000008016> {length = 2, path = 0 - 1}' 

这样的崩溃似乎只有在我们切换到iOS 8 SDK后才开始在我们的代码中发生。

为什么发生这种情况?

注意:我已经知道问题的答案是什么了,但是在堆栈溢出和networking的其他部分,我发现很less有关于这个崩溃的信息。 我会在下面回答。 这个错误带我的同事和我三天追查,所以希望这个职位会节省别人很多时间和挫折。 我已经提交了这个与苹果的错误。

事故发生在以下情况:

我们有一个集合视图控制器,在其上呈现另一个视图控制器。

虽然集合视图控制器不再可见,但是响应于我们的应用程序的后端请求,偶尔会发生以下一系列事件。

  1. [UICollectionView insertItemsAtIndexPaths:]在隐藏的UICollectionViewController的集合视图中被调用了50个项目。
  2. 在隐藏的集合视图上调用了[UICollectionView reloadData]
  3. 会出现短暂的延迟。
  4. 隐藏的collections视图中的项目数量被设置为一个很小的数字。
  5. [UICollectionView reloadData]被再次调用。
  6. 视图控制器被解散,揭示隐藏的collections视图控制器。

内部UIKit类UICollectionViewData的断言失败将发生在第6步。

所以,这个教训是,尽量避免操纵屏幕上不可见的集合视图。

我们对这个问题的解决方法是在关键点调用[UICollectionView reloadSections:]而不是[UICollectionView reloadData]

我们怀疑reloadData的影响在未来会被推迟到某个时间点,因此,如何与其他方法调用(如insertItemsAtIndexPaths进行交互,会产生一些细微的问题,而reloadSections会立即处理,使集合视图处于更好的状态。

我们认为,直到我们开始构build我们的iOS 8应用程序之前,我们才看到这种行为。

睡得好,我的朋友们!

对我来说,这是UICollectionViewLayoutAttribute的数组。 我在UICollectionViewLayout使用它来存储项目的属性。

我忘了在prepareLayout方法中清空它。

所以layoutAttributesForItemAtIndexPath为indexPath返回了不正确的值,导致了相同的崩溃。

在prepareLayout的开头只有一个removeAll ,它正在工作。

我一直在研究这个相同的错误一段时间,并认为我已经find了另一个错误的来源,在iOS 7上,但在iOS 8上工作正常,导致相同的确切的错误:自动布局!

我正在使用embedded了UICollectionViews的控件,一个网格。 我注意到通过黑客代码来删除UICollectionViewLayoutAttributes时,与UICollectionView数据不匹配,导致崩溃,我认为其他控件放错了位置。

我的collections内容是“静态的”,在加载时加载,所以不可能进行无保护的更改。 再次,这与iOS 8完美的作品。

所以,我禁用了这个视图的自动布局function和BINGO! 崩溃消失了。 自动布局正在玩内部的UICollectionSize,因此 – (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect方法正在返回混合结果。

我试过reloadData,reloadSections,没有什么,但这个工程!

希望这将有助于其他人与UIKitexception与这个控制。

collectionViewLayoutcaching属性。 在viewwillappear中 – 创build一个新的collectionViewLayout实例并将其分配给collectionview.collectionViewLayout通过这种方式,所有caching的属性将在重新加载之前清除您的问题可能已解决。 为我工作,特别是当您使用其他collectionViewLayout库。

这帮助了我:

 cell.collectionView.collectionViewLayout.invalidateLayout() cell.collectionView.reloadData() cell.collectionView.layoutSubviews() 

Xcode 8 – Swift 3

在我的情况下,这个错误是由Autolayout引起的; 我有一个collectionViewembedded到一个隐藏的UIView,通过设置它的高度为0,当collectionView是空的,当我需要再次显示collectionView时返回150。

我设法通过调用删除该错误

collectionView.collectionViewLayout.invalitdateLayout()

在运行在superView上调用layoutIfNeeded()调用的代码之前。 现在很顺利

我希望它可以帮助未来的人。

 var sponsoredPlaceSummaries: [PlaceSummary] = [] { didSet { if sponsoredPlaceSummaries.isEmpty { self.sponsoredPlacesViewHeight.constant = 0 self.collectionView.collectionViewLayout.invalidateLayout() UIView.animate(withDuration: 1.0, delay: 0, options: .curveEaseInOut, animations: { self.view.layoutIfNeeded() }, completion: nil) } else if self.sponsoredPlacesViewHeight.constant != 150 { self.sponsoredPlacesViewHeight.constant = 150 UIView.animate(withDuration: 1.0, delay: 0, options: .curveEaseInOut, animations: { self.view.layoutIfNeeded() }, completion: nil) } } 

我遇到了同样的问题。 在我的情况下,我有2个UICollectionView在屏幕上,他们有相同的大小。

所以我重复使用相同的UICollectionViewLayout作为初始参数< – 这就是问题所在。

2 UICollectionView应该使用不同的UICollectionViewLayout参数。 所以为第二个UICollectionView创build另一个UICollectionViewLayout。

对我来说,这与@德鲁的回答有关(我的collections视图不在屏幕上)。 我正在操作collectionView的高度约束来在没有数据时将其折叠。 它导致了这个崩溃(有时候!)。 我把collectionView放在另一个视图中,并重新分配@IBOutlet到这个新视图的高度约束。 并使collectionView的高度保持不变。 崩溃已经消失了!

确保您的数据源和委托为collectionview连接到正确的视图控制器。 我有一次崩溃,因为我意外地丢弃了我的Main.Storyboard中的更改,并且由于其中的数据源和代表已经断开连接

我得到了同样的错误,但是这种错误发生在一个非常随机的时代,因为我无法一直重新创build这个错误。 我正在使用customLayout手动设置项目的属性。 我会在我的真正的iPhone上做一件事情,但会在xCode模拟器上起作用。 最后修复我的问题是使用collectionView.reloadData()而不是collectionView.reloadSections([mySectionNum])。 我不知道为什么有时候这是有效的,而不是其他的。 似乎它应该一直崩溃,但事实并非如此。 也不知道为什么这个修复工程。