造成iOS崩溃的原因是什么? UICollectionView接收具有不存在的索引路径的单元格的布局属性

时间:2014-12-16 23:13:04

标签: ios objective-c uicollectionview

我正在开发一款具有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,这样的崩溃似乎才开始在我们的代码中出现。

为什么会这样?

注意:我已经知道问题的答案是什么,但我发现很少有关于Stack Overflow和网络其他部分崩溃的信息。我将在下面发布答案。这个错误让我的同事和我三天追踪,所以希望这篇文章能为其他人节省很多时间和挫折。我已经向Apple提交了这个错误。

10 个答案:

答案 0 :(得分:27)

崩溃发生在以下情况:

我们有一个集合视图控制器,它在它上面显示另一个视图控制器。

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

  1. [UICollectionView insertItemsAtIndexPaths:]被召唤50 隐藏UICollectionViewController
  2. 的集合视图上的项目 在隐藏的集合视图中调用了
  3. [UICollectionView reloadData]
  4. 会发生短暂的延迟。
  5. 隐藏集合视图中的项目数设置为较小的数字。
  6. [UICollectionView reloadData]再次被召唤。
  7. 视图控制器被解除,显示隐藏的集合视图控制器。
  8. 内部UIKit类UICollectionViewData中的断言失败将在步骤6发生。

    所以,经验教训是,尽量避免操纵在屏幕上看不到的集合视图。

    我们解决此问题的方法是在关键点呼叫[UICollectionView reloadSections:]而不是[UICollectionView reloadData]

    我们怀疑reloadData的影响将来会推迟到某个时刻,因此可能会出现与insertItemsAtIndexPaths之类的其他方法调用相互作用的细微问题,而reloadSections立即处理,使集合视图处于更好的状态。

    我们认为在我们开始为iOS 8构建应用程序之前,我们没有看到这种行为。

    好好睡觉,我的朋友们!

答案 1 :(得分:22)

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

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

因此layoutAttributesForItemAtIndexPath返回了不正确的indexPath值,导致同样的崩溃。

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

答案 2 :(得分:8)

collectionViewLayout缓存属性。 在viewwillappear中 - 创建collectionViewLayout的新实例并将其分配给collectionview.collectionViewLayout 这样,所有缓存的属性都将在重新加载之前清除 您的问题可能已得到解决。为我工作,尤其是在使用其他collectionViewLayout库时。

答案 3 :(得分:6)

我一直在研究这个相同的bug并且认为我在iOS 7上找到了另一个错误来源,但在iOS 8上工作正常,导致同样的错误:自动布局!

我使用的是一个嵌入了UICollectionViews的控件,一个网格。我注意到,当与UICollectionView数据不匹配时,通过黑客代码删除UICollectionViewLayoutAttributes,导致崩溃,我视图中的其他控件放错了位置。

我的收藏内容是&#34;静态&#34;,在加载时加载,因此不可能进行无保护的更改。这再次与iOS 8完美配合。

所以,我只禁用了此视图的自动布局功能和BINGO!崩溃消失了。 Auto-Layout正在使用内部UICollectionSize,因此 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect方法返回mixup结果。

我尝试了reloadData,reloadSections,没有任何功能,但这样做有效!

希望通过此控件可以帮助其他与UIKit异常作斗争的人。

答案 4 :(得分:4)

Xcode 8 - Swift 3

在我的情况下,这个错误是由Autolayout引起的;我有一个嵌入到UIView中的collectionView,我将其隐藏,当collectionView为空时将其高度设置为0,当我需要再次显示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)
            }
        } 

答案 5 :(得分:3)

尝试调用layoutIfNeeded()

 cell.collectionView.collectionViewLayout.invalidateLayout()

 cell.collectionView.layoutIfNeeded()

 cell.collectionView.reloadData()

答案 6 :(得分:1)

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

所以我重复使用相同的UICollectionViewLayout作为初始参数&lt; - 这就是问题。

2 UICollectionView应该使用不同的UICollectionViewLayout参数。所以只是新的另一个UICollectionViewLayout用于第二个UICollectionView。

答案 7 :(得分:1)

对我而言,这与@Drew的答案有关(我的收藏视图在屏幕外)。当没有数据时,我正在操纵collectionView的高度约束来折叠它。它导致了这次崩溃(有时!)。我将collectionView放在另一个视图中,并将@IBOutlet重新分配给这个新视图的高度约束。并使collectionView的高度保持不变。崩溃已经一去不复返了!

答案 8 :(得分:0)

确保您的数据源&amp; collectionview的代表连接到正确的视图控制器。我曾经遇到过这次崩溃,因为我意外地丢弃了我的Main.Storyboard&amp;由于哪个数据源&amp;代表们离开了

答案 9 :(得分:0)

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