iOS 10 错误:UICollectionView 收到了索引路径不存在的单元格的布局属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39867325/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS 10 bug: UICollectionView received layout attributes for a cell with an index path that does not exist
提问by cmacera
Running my app in a device with iOS 10 I get this error:
在装有 iOS 10 的设备上运行我的应用程序时出现此错误:
UICollectionView received layout attributes for a cell with an index path that does not exist
UICollectionView 接收到的单元格的布局属性,其索引路径不存在
In iOS 8 and 9 works fine. I have been researching and I have found that is something related to invalidate the collection view layout. I tried to implement that solution with no success, so I would like to ask for direct help. This is my hierarchy view:
在 iOS 8 和 9 中工作正常。我一直在研究,我发现这与使集合视图布局无效有关。我试图实施该解决方案但没有成功,所以我想寻求直接帮助。这是我的层次结构视图:
->Table view
->Each cell of table is a custom collection view [GitHub Repo][1]
->Each item of collection view has another collection view
What I have tried is to insert
我试过的是插入
[self.collectionView.collectionViewLayout invalidateLayout];
In the
在里面
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
of both collection views.
两个集合视图。
Also I have tried to invalidate layout before doing a reload data, does not work...
此外,我尝试在重新加载数据之前使布局无效,但不起作用...
Could anyone give me some directions to take?
谁能给我一些方向?
回答by Katrin Annuk
This happened to me when number of cells in collectionView changed. Turns out I was missing invalidateLayout after calling reloadData. After adding it, I haven't experienced any more crashes. Apple has made some modifications to collectionViews in iOS10. I guess that's the reason why we are not experiencing same problem on older versions.
当 collectionView 中的单元格数量发生变化时,这发生在我身上。结果我在调用 reloadData 后丢失了 invalidateLayout。添加它后,我没有遇到任何崩溃。苹果对 iOS10 中的 collectionViews 做了一些修改。我想这就是为什么我们在旧版本上没有遇到同样问题的原因。
Here's my final code:
这是我的最终代码:
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
回答by ArturC
When you have custom layout, remember to clear cache (UICollectionViewLayoutAttributes) while overriding prepare func
当你有自定义布局时,记得在覆盖 prepare func 时清除缓存 (UICollectionViewLayoutAttributes)
override func prepare() {
super.prepare()
cache.removeAll()
}
回答by Aximem
I also faced this issue with 2 collectionViews in the same view because I added the same UICollectionViewFlowLayout in both collections :
我在同一个视图中也遇到了 2 个 collectionViews 的这个问题,因为我在两个集合中添加了相同的 UICollectionViewFlowLayout :
let layout = UICollectionViewFlowLayout()
collectionView1.collectionViewLayout = layout
collectionView2.collectionViewLayout = layout
Of course it crashes on reload data if collectionView1 Data change. If this could help someone.
当然,如果 collectionView1 数据发生变化,它会在重新加载数据时崩溃。如果这可以帮助某人。
回答by Andrey
Previous answer helps, but if you use autoresizing cells, their size will be incorrect.
以前的答案有帮助,但如果您使用自动调整大小的单元格,它们的大小将不正确。
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.estimatedItemSize = CGSizeMake(60, 25);
layout.itemSize = UICollectionViewFlowLayoutAutomaticSize;
self.collectionView.collectionViewLayout = layout;
I solve this issues by replacing
我通过替换解决了这个问题
[self.collectionView reloadData];
to
到
[self.collectionView reloadSections:indexSet];
回答by m8labs
The @Katrin's answer helped a lot, but I could achieve even better results by adding one more line:
@Katrin 的回答很有帮助,但我可以通过再添加一行来获得更好的结果:
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
collectionView.layoutSubviews() // <-- here it is :)
I can't now say if I could reproduce crash with this line or not, but I guess there was one... So, still not a silver bullet, but something.
我现在不能说我是否可以用这条线重现崩溃,但我想有一个......所以,仍然不是灵丹妙药,而是一些东西。
回答by krlbsk
Resetting UICollectionView
's layout solved the problem for me:
ResetUICollectionView
的布局为我解决了这个问题:
let layout = UICollectionViewFlowLayout()
collectionView?.collectionViewLayout = layout
回答by Nick Kallen
Calling invalidateLayout
did not prevent the crash in my case. (It worked if the number of items in the collection view increased but not if it decreased). Context: I have a UICollectionView inside a UITableViewCell and when the table cell is re-used I reset the delegates of the collectionView. I fixed the problem not by invalidating the cache but by RECREATING the layout object any time I reset the delegate, then calling reloadData():
invalidateLayout
在我的情况下,呼叫并没有阻止崩溃。(如果集合视图中的项目数量增加则有效,但如果减少则无效)。上下文:我在 UITableViewCell 中有一个 UICollectionView,当重新使用表格单元格时,我重置了 collectionView 的委托。我不是通过使缓存无效而是通过在重置委托时重新创建布局对象来解决问题,然后调用 reloadData():
foo.dataSource = newDataSource
foo.delegate = newDelegate
foo.fixLayoutBug()
foo.reloadData()
func fixLayoutBug() {
let oldLayout = collectionViewLayout as! UICollectionViewFlowLayout
let newLayout = UICollectionViewFlowLayout()
newLayout.estimatedItemSize = oldLayout.estimatedItemSize
newLayout.footerReferenceSize = oldLayout.footerReferenceSize
newLayout.headerReferenceSize = oldLayout.headerReferenceSize
newLayout.itemSize = oldLayout.itemSize
newLayout.minimumInteritemSpacing = oldLayout.minimumInteritemSpacing
newLayout.minimumLineSpacing = oldLayout.minimumLineSpacing
newLayout.scrollDirection = oldLayout.scrollDirection
newLayout.sectionFootersPinToVisibleBounds = oldLayout.sectionFootersPinToVisibleBounds
newLayout.sectionHeadersPinToVisibleBounds = oldLayout.sectionHeadersPinToVisibleBounds
newLayout.sectionInset = oldLayout.sectionInset
newLayout.sectionInsetReference = oldLayout.sectionInsetReference
collectionViewLayout = newLayout
}
回答by jeff ayan
In my case, I was changing the NSlayoutConstraint constant
就我而言,我正在更改 NSlayoutConstraint 常量
self.collectionViewContacts.collectionViewLayout.invalidateLayout()
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
self.collectionViewContacts.reloadData()
solved the issue
解决了这个问题
回答by Kevin Bel
It's not the best to reloadData everytime (You should use insertItems and deleteItems, and even reloadSections). But... after saying that in some cases it's a valid so, you can actually do this:
每次都重新加载数据并不是最好的(您应该使用 insertItems 和 deleteItems,甚至是 reloadSections)。但是......在说在某些情况下它是有效的之后,你实际上可以这样做:
collectionView.dataSource = nil
collectionView.delegate = nil
/*... All changes here. ... */
collectionView.dataSource = self
collectionView.delegate = self
collectionView.reloadData()
回答by Mol0ko
I had the problem using RxDataSourceswith RxCollectionViewSectionedAnimatedDataSource
and solved it by combining two answers. I have to invalidateLayout()
when reactively reload my collection:
我在使用RxDataSources时遇到了问题,RxCollectionViewSectionedAnimatedDataSource
并通过结合两个答案来解决它。invalidateLayout()
当我被动地重新加载我的收藏时,我必须这样做:
...
.asDriver(onErrorJustReturn: [])
.do(onNext: { [weak self] _ in
DispatchQueue.main.async {
self?.collectionViewLayout.invalidateLayout()
self?.collectionView.layoutSubviews()
}
}).drive(collectionView.rx.items(dataSource: collectionController.dataSource))
.disposed(by: disposeBag)
and clear cache
array(s) in prepare()
layout method. Here is the code:
并cache
在prepare()
布局方法中清除数组。这是代码:
override func prepare() {
super.prepare()
cache.removeAll()
guard let collectionView = collectionView,
collectionView.numberOfSections > 0,
let delegate = delegate else {
return
}
...