iOS15及以上Self sizing Collection View调用layoutSubviews递归崩溃
问题根因
该问题是iOS 15对UICollectionView布局逻辑调整后触发的:
- iOS 15新增了UICollectionView布局递归检测机制,当检测到布局更新进入无限循环时会直接抛出异常,iOS 14及更低版本没有该检测逻辑,所以不会崩溃。
- 原有代码存在多处冗余的布局更新触发逻辑,刚好满足递归循环的条件:
- 重写的
layoutSubviews中调用invalidateIntrinsicContentSize后,会触发系统重新计算视图尺寸,进而再次调用layoutSubviews,形成第一重循环。 contentSize的didSet钩子会触发invalidateIntrinsicContentSize,而intrinsicContentSize直接返回contentSize,二者形成第二重联动循环。reloadData中强制调用layoutIfNeeded会提前触发布局计算,和前两个逻辑叠加后直接触发递归检测。
- 重写的
修复方案
删除冗余的触发逻辑,仅保留必要的自适应尺寸代码即可,修改后代码如下:
class DynamicCollectionView: UICollectionView { override var contentSize: CGSize { didSet { // 仅当尺寸真实变化时才触发更新,避免无效调用 if contentSize != intrinsicContentSize { invalidateIntrinsicContentSize() } } } override var intrinsicContentSize: CGSize { return contentSize } override func reloadData() { super.reloadData() invalidateIntrinsicContentSize() } }
额外注意事项:
- 要保证该CollectionView的自动布局约束没有添加固定宽高限制,才可以正常跟随contentSize自适应尺寸。
- 如果需要仅自适应高度/宽度某一个维度,可以在
intrinsicContentSize的实现中固定另一个维度的返回值即可。
内容的提问来源于stack exchange,提问作者Deepa Bhat
相关产品推荐
相关产品推荐

