UICollectionView 过时数据的断言错误

Posted

技术标签:

【中文标题】UICollectionView 过时数据的断言错误【英文标题】:UICollectionView assertion error on stale data 【发布时间】:2013-08-20 15:26:27 【问题描述】:

在尝试从我的收藏视图中卸载一批图像然后用另一批替换它们的过程中,我遇到了一个错误,具体取决于原始图像组或后续图像组是否多于或少于预期替换,发生断言错误:

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

在这种情况下,现有的图像计数列表为 5,而新的图像计数列表为 2。因此,当它到达第三张图像时 - 发生了异常 - 表明 UI CollectionViewDataDelegate 不知道数据流。

有关如何确保 UICollectionView 引用新图像的任何建议?当然,我已经调用了“reloadData”……

谢谢

【问题讨论】:

对象正在访问一些陈旧数据的痕迹 - 因此搜索单元格,其索引可能超出该部分中引用的当前数据的范围。就我而言,经过多次实验,补救措施似乎是“[self.collectionView reloadSections:sections];”。完成此操作后,当我向左或向右滑动 collectionView 时,不再断言异常。 我遇到了类似的问题。我有两个显示相同数据的 UICV。当用户在应用程序中更改日期时,我请求新数据,然后在两个 CV 上调用 reloadData。这在 ios6.1 中运行良好。当我在较新的版本上运行应用程序时,出现上述错误。切换到 reloadSections:sections 可以修复它,但会添加不需要的延迟和动画(自定义流布局)。你在这方面有什么进展吗? 当我根据数据源返回的每个部分的节数和项目数返回具有不应该存在的索引路径的布局属性时,我遇到了这个问题!我花了一段时间才弄清楚这一点。如果您有动态模型,请确保部分/项目路径与布局属性路径对齐。 【参考方案1】:

我遇到了同样的问题。代码在 6.1 下运行,在 7.0 下崩溃 我通过以下方式解决了这个问题:

在函数中

-(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView

我打电话

[myCollectionView.collectionViewLayout invalidateLayout];

就是这样。

【讨论】:

谢谢!我知道我必须使布局无效,但只有在这种方法中调用它才对我有用。 对我来说,在我拨打 reloadData 之前拨打 invalidateLayout 很有效。 谁能解释为什么invalidateLayout 解决了这个问题?我在尝试更改 dataSourcedelegatecollectionViewLayout 时遇到了同样的问题。 个人认为将invalidate放在numberOfSectionsInCollectionView中是个坏主意:它可能被调用得太频繁了。只有当数据如上变化时才调用它。 对我来说,只有当我从 numberOfSectionsInCollectionView 调用 invalidateLayout 时它才有效。如果我在其他任何地方调用它(包括在主线程等上重新加载数据方法之前),它就会崩溃。【参考方案2】:

对于 iOS 10 和 11,这会有所帮助:

collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()

无效布局应该在重新加载数据之后。

【讨论】:

在 iOS 11 上也帮助了我【参考方案3】:

Dominic Sander 和user1544494 都是对的,他们的解决方案也很好。

不幸的是,我注意到如果您设置minimumLineSpacingForSectionAtIndexminimumInteritemSpacingForSectionAtIndex,您的collectionView 的外观将会损坏(迟早)。

invalidateLayout 放入viewWillLayoutSubviews 可以回答这个问题并有助于保留viewCollection 的外观。

- (void)viewWillLayoutSubviews

    [super viewWillLayoutSubviews];
    [viewCollection.collectionViewLayout invalidateLayout];

【讨论】:

我非常喜欢这个解决方案,干净且直观。谢谢! 在把它放到我的集合视图控制器之后,我有方法-viewWillLayoutSubviews 可以被无限调用。视图层次结构应该是什么才能使其工作?【参考方案4】:

这很简单。 就像下面这句话一样。

'UICollectionView recieved layout attributes for a cell with an 
index path that does not exist: <NSIndexPath: 0xb141c60> length = 2, path = 0 - 2

这意味着dataSouce上没有indexPath(0,2)。 但是,您的 UICollectionViewLayout 会为 indexPath(0,2) 返回一个 UICollectionViewLayoutAttributes。

你应该返回 UICollectionViewLayoutAttributes 只存在于 dataSouce 上。


我认为它是从 iOS7 更改的。

【讨论】:

你说得对。还必须更新底层数据源/布局。 我的同事上个月发现了另一个案例。更新 UICollectionView 的 contentInsets 将导致更新布局。因此,(1)dataSourceChanged, (2)setContentInsets -> Crash 例外。 (1)dataSourceChanged, (2)reloadData series(Section, insertXXX 等等) (3)setContentInsets -> 安全。从 iOS 11 可能会遇到这种情况。【参考方案5】:

我的问题是我在一个UIViewController 中有两个UICollectionViews。我将两个UICollectionViews 都连接到同一个UICollectionViewLayout 子类。我通过将每个 UICollectionView 更改为拥有自己的 UICollectionViewLayout 子类来解决此问题。

来源:This Question

【讨论】:

你拯救了我的一天,伙计!【参考方案6】:

我通过更新我的集合视图数据源修复了这个崩溃:

- (NSInteger)collectionView:(UICollectionView *)collectionView
     numberOfItemsInSection:(NSInteger)section

    [collectionView.collectionViewLayout invalidateLayout];
    return collectionArray.count;

【讨论】:

collectionArray 大小变化时调用,不在此方法中。 invalidateLayout 不应在数据源方法中调用【参考方案7】:

我也遇到了同样的崩溃。

在我的应用程序中,问题是我没有使用 UICollectionViewLayoutAttributes 清空数组。我在 prepareLayout() 方法中使用它来存储每个单元格的布局属性。

var itemAttributes: Array&lt;UICollectionViewLayoutAttributes&gt; = Array&lt;UICollectionViewLayoutAttributes&gt;()

仅在 prepareLayout 的第一行中使用 self.itemAttributes.removeAll(),它就可以工作。

【讨论】:

【参考方案8】:

我在修改 Collection View 的内容后遇到了这个问题。在我的案例中有效的解决方案是在重新加载后使布局无效。在重新加载之前这样做是行不通的。

[collectionView reloadData];

//forces the layout attributes to be recalculated for new data
[collectionView.collectionViewLayout invalidateLayout];

【讨论】:

【参考方案9】:

我找到的解决方案是确保我在layoutAttributesForElementsInRect(rect: CGRect) -&gt; [AnyObject]? 方法中创建的indexPath 对该行有效。以前,我使用的是(i 是我的循环计数器):

var indexPath = NSIndexPath(index: i)
var attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)

但更新它以使用以下解决了它:

var indexPath = NSIndexPath(forRow: i, inSection: 0)!
var attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)

【讨论】:

【参考方案10】:

我能够通过创建UICollectionViewFlowLayout 的子类并覆盖此方法以返回YES 来解决此问题:

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

    return YES;

【讨论】:

【参考方案11】:

我遇到过这个问题,很烦人。我的解决办法是忘记UICollectionViewController,而是使用常规的UIViewController 和内部的UICollectionView

【讨论】:

【参考方案12】:

确保更新您的collectionViewLayoutcontentSize。所以在获得新图像(2,而不是 5)后,重新计算 contentSize 并设置它。

【讨论】:

【参考方案13】:

我也遇到过这个错误并找到了解决方法。对我来说,UICollectionView 是在 iOS 7 下启动的,在 iOS 8 上完美运行。

查看这篇文章:What's causing this iOS crash? UICollectionView received layout attributes for a cell with an index path that does not exist

简而言之:自动布局。在包含 UICollectionView 的视图上禁用它,对我来说,它有效。

【讨论】:

【参考方案14】:

collectionViewLayout 缓存布局属性。 在视图中会出现。创建一个新的 collectionViewLayout 实例并将其分配给 collectionview.collectionViewLayout 这样,所有缓存的属性将在重新加载之前清除 您的问题可能会得到解决。为我工作,尤其是当您使用其他 collectionViewLayout 库时。

【讨论】:

【参考方案15】:

我有类似的问题(使用 Swift2.0,XCode 7)。

应用程序因UICollectionView received layout attributes for a cell with an index path that does not exist而崩溃...

在我的例子中,由于我使用了故事板,结果我忘记将我的 viewController 中定义的 IBOutlet 与故事板中定义的实际 collectionView 连接起来。将两者连接可以解决问题。

【讨论】:

【参考方案16】:

我想通了。 如果你使用 nib/xib 来组织你的UITableViewCell 和嵌套的UICollectionView,你可以通过重写这个方法来避免这个错误。

- (void)prepareForReuse 

    [super prepareForReuse];
    [self.collectionView.collectionViewLayout invalidateLayout];

希望对你有帮助。

【讨论】:

【参考方案17】:

这意味着dataSouce上没有indexPath(0,2)。但是,您的 UICollectionViewLayout 返回 indexPath(0,2) 的 UICollectionViewLayoutAttributes。作者:TopChul

没错!对我来说,问题的发生是因为我对两个 collectionView 使用了 same collection layout(instance)!这样布局就混淆了两个集合视图。

在不同的集合视图之间使用不同的布局后它工作正常。

【讨论】:

【参考方案18】:

我在尝试将集合视图复制到另一个故事板时遇到了类似的情况。

'UICollectionView 接收到带有索引的单元格的布局属性 不存在的路径:length = 2, path = 1 - 0'

起初,我正在寻找快速解决方案。尝试复制粘贴各种 *** 答案。

但是我写了自己的布局类。所以我尝试谨慎地调试,这可能是我的执行问题,对吧?发现从未调用过numberOfSections 方法。集合视图假设它只有一个部分。

然后我发现视图控制器类忘记符合UICollectionViewDataSource。虽然 dataSource 已连接到情节提要中,但视图控制器类可能会被向下转换,例如 if let ds = dataSource as? UICollectionViewDataSource ds.numberOfSections...,它会静默失败。

所以我添加了对UICollectionViewDataSource 的一致性,一切正常。我的猜测可能不准确。但教训是每当有一个你不熟悉的错误时,安顿下来并理解它。 UICollectionView 接收到的单元格的布局属性具有不存在的索引路径,这正是它所说的。没那么难吧?不要试图找到灵丹妙药,就像这里的许多答案一样。它们都很棒,但你的代码才是真正的战场。

【讨论】:

【参考方案19】:

当我将UICollectionViewFlowLayout 用作CollectionView's collectionViewLayout 时,我遇到了同样的问题。

声明父viewController实现UICollectionViewDelegateFlowLayout并将其分配为collectionView的委托可以解决这个问题。

【讨论】:

【参考方案20】:

就我而言,我有一个自定义 UICollectionViewFlowLayout。从 collectionView 中删除单元格后,应用程序崩溃了。修复是针对removeAll() 先前计算的属性。所以,override func prepare() 之后的第一行是arrayHoldingYourAttributes.removeAll()

【讨论】:

【参考方案21】:

你好,我在将一个 collectionView 插入另一个 collectionView 并在主队列中重新加载数据时遇到了同样的问题。最后,我在新数据转换为 collectionView 之前重新加载数据。

dispatch_async(dispatch_get_main_queue(), ^
    [_collectionView reloadData];
);

_notes = notes;

[_collectionView reloadData];

【讨论】:

以上是关于UICollectionView 过时数据的断言错误的主要内容,如果未能解决你的问题,请参考以下文章

-[UICollectionView _endItemAnimations] 崩溃中的断言失败

IOS UICollectionView 在使用两个集合视图时抛出断言

-[UICollectionView _endItemAnimations] 中的 UICollectionView 断言失败

UICollectionView 上的断言失败

带有 endItemAnimations 的 UICollectionView 中的断言失败

UICollectionView + iOS 7 / Xcode 5 = 断言失败