在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
两个集合视图。
我也尝试在重新加载数据之前使布局无效,不起作用......
有人能给我一些指示吗?
当collectionView中的单元格数量发生变化时,就会发生这种情况。原来我在调用reloadData后缺少invalidateLayout。添加后,我没有遇到任何更多的崩溃。 Apple已经对iOS10中的collectionView进行了一些修改。我猜这就是我们在旧版本上没有遇到同样问题的原因。
这是我的最终代码:
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
如果你想保持滚动位置并修复崩溃,你可以使用:
collectionView.reloadData()
let context = collectionView.collectionViewLayout.invalidationContext(forBoundsChange: collectionView.bounds)
context.contentOffsetAdjustment = CGPoint.zero
collectionView.collectionViewLayout.invalidateLayout(with: context)
我也有这个问题。在我的情况下,有一个自定义UICollectionViewLayout
应用于集合视图,问题是它有应该显示的单元格数的陈旧数据。当你看到UICollectionView received layout attributes for a cell with an index path that does not exist
时,这绝对是你可以检查的东西
我设法通过在调用collectionViewLayout
之前重新创建reloadData()
来解决这个问题
问题可能与我有一个单独的dataSource
实例(即不是持有collectionView的视图控制器)有关,并且在交换数据源时,可能会出现崩溃。
这也发生在我身上,但这是因为我的UICollectionViewDataSource
改变了,我没有打电话给-[UICollectionView reloadData]
。就我而言,我有以下数据结构:
struct Bar { let name: String }
struct Foo { let name: String; let bars: [Bar] }
我有两个UICollectionView
s:一个用于Foo
s,一个用于Bar
s。在我的-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;
}
}
没有-reloadData
调用,我会在旋转设备时看到崩溃。
花了两天时间后,下面的代码解决了这个问题。在加载集合视图之前,请编写以下代码。
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
collecView.collectionViewLayout = flowLayout
collecView.delegate = self
collecView.dataSource = self
collecView.reloadData()
然后崩溃将被解决,但您会在集合视图单元格中发现问题,因为单元格是按照您的设计压缩或不压缩。然后在scrolldirection行之后只有一行代码
flowLayout.itemSize = CGSize(width: 92, height: 100)
使用上面的代码行,您可以调整集合视图单元格布局。
我希望它能帮助别人。
在我的情况下,我正在改变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
}
希望它可以帮助某人
以下是我的意思:
[self.collectionView reloadData];
[self.collectionView layoutIfNeeded];
这段代码似乎迫使collectionView在重新加载数据之前滚动到第一个单元格,这似乎在我的情况下导致错误。
当您有自定义布局时,请记住在覆盖prepare func时清除缓存(UICollectionViewLayoutAttributes)
override func prepare() {
super.prepare()
cache.removeAll()
}
我也在同一个视图中遇到了2个collectionViews的问题,因为我在两个集合中都添加了相同的UICollectionViewFlowLayout:
let layout = UICollectionViewFlowLayout()
collectionView1.collectionViewLayout = layout
collectionView2.collectionViewLayout = layout
当然,如果collectionView1数据发生变化,它会在重载数据时崩溃。如果这可以帮助某人。
以前的答案有帮助,但如果您使用自动调整单元格,它们的大小将不正确。
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.estimatedItemSize = CGSizeMake(60, 25);
layout.itemSize = UICollectionViewFlowLayoutAutomaticSize;
self.collectionView.collectionViewLayout = layout;
我通过替换来解决这个问题
[self.collectionView reloadData];
至
[self.collectionView reloadSections:indexSet];
@ Katrin的回答帮了很多忙,但我可以通过添加一行来获得更好的结果:
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
collectionView.layoutSubviews() // <-- here it is :)
我现在不能说我是否可以用这条线重现崩溃,但我猜有一条......所以,仍然不是一颗银弹,而是一些东西。
在我的情况下,调用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
}
每次reloadData都不是最好的(你应该使用insertItems和deleteItems,甚至reloadSections)。但是...在说某些情况下它是有效的之后,你实际上可以这样做:
collectionView.dataSource = nil
collectionView.delegate = nil
/*... All changes here. ... */
collectionView.dataSource = self
collectionView.delegate = self
collectionView.reloadData()
就我而言,我正在改变NSlayoutConstraint常量
self.collectionViewContacts.collectionViewLayout.invalidateLayout()
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
self.collectionViewContacts.reloadData()
解决了这个问题
重置UICollectionView
的布局为我解决了这个问题:
let layout = UICollectionViewFlowLayout()
collectionView?.collectionViewLayout = layout