iOS14调用setCollectionViewLayout崩溃,iOS16正常求助
iOS14.1切换UICollectionView布局崩溃的解决方案
问题分析
崩溃日志显示调用-[__NSDictionaryM setObject:forKey:]时传入了nil对象,key对应cell的indexPath。结合系统版本差异和代码逻辑,核心原因是iOS14的UICollectionView布局系统在处理复用cell indexPath的装饰视图时存在兼容性bug:
- 代码中为分隔符装饰视图使用了与对应cell完全相同的indexPath
- iOS16对布局属性的处理逻辑做了优化,规避了该冲突,但iOS14中系统尝试将装饰视图属性存入内部字典时会出现nil对象
- 另一个ViewController在iOS14环境下正常,大概率是布局切换时的数据源状态、布局类型差异刚好避开了这个bug
具体修复方案
1. 为装饰视图生成独立的IndexPath
避免与cell的indexPath重复,修改layoutAttributesForElements方法中创建装饰视图属性的代码:
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes] { let layoutAttributes = super.layoutAttributesForElements(in: rect) ?? [] let lineWidth: CGFloat = Const.minimumLineSpacing var decorationAttributes: [UICollectionViewLayoutAttributes] = [] // 跳过第一个cell for layoutAttribute in layoutAttributes where layoutAttribute.indexPath.item > 0 { // 生成独立的indexPath,避免与cell的indexPath冲突 let decorationIndexPath = IndexPath(item: layoutAttribute.indexPath.item + Int.max / 2, section: layoutAttribute.indexPath.section) let separatorAttribute = UICollectionViewLayoutAttributes(forDecorationViewOfKind: "separator", with: decorationIndexPath) let cellFrame = layoutAttribute.frame separatorAttribute.frame = CGRect(x: cellFrame.origin.x, y: cellFrame.origin.y - lineWidth, width: cellFrame.size.width, height: lineWidth) separatorAttribute.zIndex = Int.max decorationAttributes.append(separatorAttribute) } return layoutAttributes + decorationAttributes }
2. 调整prepare方法的调用顺序
确保先执行父类的prepare方法初始化布局基础参数,再设置自定义的itemSize:
override func prepare() { super.prepare() // 先调用父类方法完成基础初始化 guard let collectionView = collectionView, collectionView.numberOfSections > 0 else { return } itemSize = CGSize(width: collectionView.frame.width - Const.leftRightSpacing * 2, height: itemHeight) }
3. 切换布局时的额外处理(可选)
如果上述修复仍有问题,在切换布局前先让旧布局失效,确保系统清理旧的布局属性:
collectionView.collectionViewLayout.invalidateLayout() collectionView.setCollectionViewLayout(mode.layout, animated: false)
验证
完成修改后,在iOS14.1环境下测试布局切换,确认崩溃不再出现;同时验证iOS16环境下功能保持正常。
内容的提问来源于stack exchange,提问作者Omeir Ahmed
相关产品推荐
相关产品推荐

