自调整大小的集合视图在 iOS 15 中进入递归循环

Posted

技术标签:

【中文标题】自调整大小的集合视图在 iOS 15 中进入递归循环【英文标题】:Self sizing collection view enters a recursive loop in iOS 15 【发布时间】:2021-12-03 11:12:35 【问题描述】:

我有一个自行调整大小的集合视图,当我调用 super.layoutSubviews 时,我的应用程序崩溃了,因为集合视图进入了递归更新循环。这在 ios 14 及更低版本中运行良好。但在 iOS 15 及以后的版本中观察到了。

class DynamicCollectionView: UICollectionView 

override var contentSize: CGSize 
    didSet 
        invalidateIntrinsicContentSize()
    


override func layoutSubviews() 
    super.layoutSubviews()
    if bounds.size != intrinsicContentSize 
        invalidateIntrinsicContentSize()
    


override var intrinsicContentSize: CGSize 
    return contentSize


override func reloadData() 
    super.reloadData()
    invalidateIntrinsicContentSize()
    layoutIfNeeded()

崩溃说:

由于未捕获的异常而终止应用程序 'NSInternalInconsistencyException',原因:'UICollectionView () 卡在它的 更新/布局循环。发生这种情况的原因有很多,包括 首选属性不返回的自调整视图 大小一致。要调试此问题,请检查控制台应用程序的日志 在“UICollectionViewRecursion”类别中。'

【问题讨论】:

同***.com/questions/70121104/… 但是上面的链接也没有解决方案@matt 非常正确,我没说有。我说他们是同一个问题,他们很明显是。让我们试着把事情巩固起来。同一个问题问两次是没有意义的。您可以观看另一个问题,甚至可以为其添加赏金,但仅仅重新提问并不会降低您获得答案的机会,而且会使 Stack Overflow 变得一团糟。 现在,如果您添加了足够的代码来重现该问题,那将是另一回事。但你没有。在我看来,很明显你在layoutSubviews 中做了一些非常奇怪的事情,但没有代码我不能说更多。在集合视图中让单元格自行调整大小有正确的方法和错误的方法,这看起来像是错误的方法。但同样,你没有问 如何 去做;你只是抱怨你的方式停止工作了。 有没有人找到更多相关信息?我目前在 iOS 15.2 上遇到同样的问题。我已经尝试解决这个问题几天了,到目前为止没有任何运气...... 【参考方案1】:

在我们的例子中(垂直流布局collioview,垂直自调整单元格),问题是我有一些单元格没有实现覆盖preferredLayoutAttributesFitting:

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes 
    let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)
    layoutAttributes.frame.size = contentView
        .systemLayoutSizeFitting(targetSize,
                                 withHorizontalFittingPriority: .required,
                                 verticalFittingPriority: .fittingSizeLevel)
    return layoutAttributes

这里是类似于我们的流程布局:

final class VerticalFlowLayout: UICollectionViewFlowLayout 
    
    override init() 
        super.init()
        scrollDirection = .vertical
        estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    
        
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? 
        let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)
        
        
        layoutAttributesObjects?.enumerated()
            .forEach  (index, layoutAttributes) in
                if layoutAttributes.representedElementCategory == .cell 
                    
                    guard let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame else 
                        return
                    
                    layoutAttributes.frame = newFrame
                
            
        
        return layoutAttributesObjects
    
    
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? 
        guard let collectionView = collectionView else 
            return nil
        
        
        guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else 
            return nil
        
        
        layoutAttributes.frame.origin.x = sectionInset.left
        layoutAttributes.frame.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right
        
        return layoutAttributes
    

因此,在 ios 15 之前的 ios 版本中,collectionview 和单元格没有问题。在为 ios 15+ 构建相同的代码后,开始卡在其更新/布局循环中。

所以,如果你有类似的问题,试着弄清楚你正在使用哪种类型的自定义布局,并尝试根据 preferredLayoutAttributesFitting 返回。

附注如果您(阅读该文章的人)有任何见解,为什么它在 ios15 之前有效而在 ios15 之后无效,ios15 中实际发生了什么变化导致了此类问题,请与我们分享,ty :)

【讨论】:

真的希望它可以帮助你或导致你自己的解决方案。【参考方案2】:

手动计算单元格大小时在 iOS15 上面临同样的崩溃。

通过将 IB 中的 collectionView 上的 Estimated Size 设置为 None 来禁用 None 对我来说是正确的。

【讨论】:

以上是关于自调整大小的集合视图在 iOS 15 中进入递归循环的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionViewCell 的高度,带有 2 个多行 UILabel / 自调整大小的集合视图单元格

如何在 iOS 中避免/禁用 Collection View 的垂直滚动

ios在表格视图单元格中视觉调整图像大小

在 iOS 上创建 Nx2 集合视图

swift中的自定义集合视图单元格

模式视图在 ios 6.0 中调整大小,工具栏位于视图中间