在iOS 10设备中运行我的应用程序时出现此错误:
UICollectionView收到索引路径不存在的单元格的布局属性
在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
我试过的是插入
[self.collectionView.collectionViewLayout invalidateLayout];
在
中- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
两个集合视图中的。
此外,我在尝试重新加载数据之前尝试使布局无效,不起作用......
有人可以给我一些指示吗?
答案 0 :(得分:121)
当collectionView中的单元格数量发生变化时,就发生了这种情况。原来我在调用reloadData后缺少invalidateLayout。添加后,我没有遇到任何更多的崩溃。 Apple已经对iOS10中的collectionView进行了一些修改。我猜这就是我们在旧版本上没有遇到同样问题的原因。
这是我的最终代码:
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
答案 1 :(得分:42)
如果您有自定义布局,请记住在覆盖prepare func时清除缓存(UICollectionViewLayoutAttributes)
override func prepare() {
super.prepare()
cache.removeAll()
}
答案 2 :(得分:17)
我也在同一视图中遇到了2个collectionViews的问题,因为我在两个集合中添加了相同的UICollectionViewFlowLayout:
let layout = UICollectionViewFlowLayout()
collectionView1.collectionViewLayout = layout
collectionView2.collectionViewLayout = layout
当然,如果collectionView1数据发生变化,它会在重新加载数据时崩溃。如果这可以帮助某人。
答案 3 :(得分:6)
以前的回答会有所帮助,但如果您使用自动调整单元格,则其大小将不正确。
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.estimatedItemSize = CGSizeMake(60, 25);
layout.itemSize = UICollectionViewFlowLayoutAutomaticSize;
self.collectionView.collectionViewLayout = layout;
我通过替换
解决了这个问题[self.collectionView reloadData];
到
[self.collectionView reloadSections:indexSet];
答案 4 :(得分:5)
@ Katrin的回答帮了很多忙,但我可以通过增加一行来取得更好的成绩:
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
collectionView.layoutSubviews() // <-- here it is :)
我现在不能说我是否可以用这条线重现崩溃,但我猜有一条......所以,仍然不是一颗银弹,而是一些东西。
答案 5 :(得分:3)
就我而言,我正在改变NSlayoutConstraint常量
self.collectionViewContacts.collectionViewLayout.invalidateLayout()
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
self.collectionViewContacts.reloadData()
解决了问题
答案 6 :(得分:3)
在我的情况下,致电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
}
答案 7 :(得分:3)
每次reloadData都不是最好的(你应该使用insertItems和deleteItems,甚至reloadSections)。 但是......在说某些情况下它是有效的之后,你实际上可以做到这一点:
collectionView.dataSource = nil
collectionView.delegate = nil
/*... All changes here. ... */
collectionView.dataSource = self
collectionView.delegate = self
collectionView.reloadData()
答案 8 :(得分:2)
重置UICollectionView
的布局为我解决了这个问题:
let layout = UICollectionViewFlowLayout()
collectionView?.collectionViewLayout = layout
答案 9 :(得分:1)
如果您想保持滚动位置并修复崩溃,可以使用:
collectionView.reloadData()
let context = collectionView.collectionViewLayout.invalidationContext(forBoundsChange: collectionView.bounds)
context.contentOffsetAdjustment = CGPoint.zero
collectionView.collectionViewLayout.invalidateLayout(with: context)
答案 10 :(得分:1)
我在将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)
,并以cache
布局方法清除prepare()
数组。这是代码:
override func prepare() {
super.prepare()
cache.removeAll()
guard let collectionView = collectionView,
collectionView.numberOfSections > 0,
let delegate = delegate else {
return
}
...
答案 11 :(得分:1)
在使用动画约束更改显示隐藏集合视图时,我遇到了类似的问题。我的解决方案基于现有的答案。
self.filtersCollectionView.reloadData()
if isNeedToUpdateConstraint {
filtersCollectionViewHeightLayoutConstraint.constant = updatedHeight
UIView.animate(withDuration: 0.1, animations: {
self.view.setNeedsLayout()
}, completion: { completion in
if completion {
self.filtersCollectionView.collectionViewLayout.invalidateLayout()
}
})
}
答案 12 :(得分:0)
我也有这个问题。在我的情况下,有一个自定义UICollectionViewLayout
应用于集合视图&amp;问题是它有应该显示的单元格数量的陈旧数据。当你看到UICollectionView received layout attributes for a cell with an index path that does not exist
答案 13 :(得分:0)
我设法通过在调用collectionViewLayout
reloadData()
来解决此问题
问题可能与我有dataSource
的单独实例(即不是持有collectionView的视图控制器)有关,而且在交换数据源时,可能会出现崩溃。
答案 14 :(得分:0)
这也发生在我身上,但这是因为我的The name 'InitializeComponent' does not exist in the current context
发生了变化,我没有打电话给UICollectionViewDataSource
。就我而言,我有以下数据结构:
-[UICollectionView reloadData]
我有两个struct Bar { let name: String }
struct Foo { let name: String; let bars: [Bar] }
s:一个用于UICollectionView
个,一个用于Foo
个。在我的Bar
中,我有以下内容:
-collectionView:didSelectItemAtIndexPath:
如果没有- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionView == self.fooCollectionView) {
self.selectedFoo = self.foos[indexPath.row];
[self.barCollectionView reloadData];
self.fooCollectionView.hidden = YES;
self.barCollectionView.hidden = NO;
} else if (collectionView == self.barCollectionView) {
// do some stuff with the selected bar
self.selectedFoo = nil;
// This -reloadData call fixed my error. I thought I didn't
// need it since my UICollectionView was hidden
[self.barCollectionView reloadData];
self.barCollectionView.hidden = YES;
self.fooCollectionView.hidden = NO;
}
}
调用,我会在旋转设备时看到崩溃。
答案 15 :(得分:0)
就我而言,我正在更改NSLayoutConstraint的常量,上述解决方案均不适用于我。感谢@jeff ayan的回答给了我提示。我用这段代码解决了问题
override func prepareForReuse() {
super.prepareForReuse()
imagesCollectionHeight.constant = 100 // changing collectionview height constant
imageContainerWidth.constant = 100 //changing width constant of some view
self.layoutIfNeeded() // this line did the trick for me
}
希望它对某人有帮助
答案 16 :(得分:0)
以下内容适合我:
[self.collectionView reloadData];
[self.collectionView layoutIfNeeded];
这段代码似乎迫使collectionView在重新加载数据之前滚动到第一个单元格,这似乎是导致我的错误的原因。