iOS 16中UICollectionView调用beginInteractiveMovementForItem崩溃求替代方案
iOS 16 下 UICollectionView 拖拽崩溃的替代方案及临时修复
问题复现
调用collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)时触发崩溃,报错信息:
attempt to insert nil object from objects[0]' terminating with uncaught exception of type NSException
临时修复与替代方案
方案1:前置校验+iOS16专属拖拽API替代
在调用方法前先校验目标Cell的有效性,同时针对iOS16改用系统现代拖拽API发起交互:
if #available(iOS 16.0, *) { guard let targetCell = collectionView.cellForItem(at: selectedIndexPath) else { return } let dragItems = collectionView.dragItems(for: selectedIndexPath) collectionView.beginInteractiveDrag(with: dragItems, at: targetCell.center, in: collectionView) } else { collectionView.beginInteractiveMovementForItem(at: selectedIndexPath) }
方案2:排查数据源与布局合法性
- 确保
collectionView(_:canMoveItemAt:)方法返回true,且拖拽过程中数据源不会返回nil数据 - 检查自定义UICollectionViewLayout的配置,iOS16对布局属性的合法性校验更严格,避免存在无效布局参数
方案3:重构为现代拖拽排序流程
完全基于UICollectionViewDragDelegate和UICollectionViewDropDelegate实现拖拽排序,这是Apple推荐的兼容性更好的方案:
- 实现拖拽数据源方法:
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { let dataItem = yourDataSource[indexPath.item] let itemProvider = NSItemProvider(object: dataItem.uniqueIdentifier as NSString) let dragItem = UIDragItem(itemProvider: itemProvider) dragItem.localObject = dataItem return [dragItem] }
- 实现拖拽接收与排序逻辑:
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) { guard let destIndexPath = coordinator.destinationIndexPath else { return } guard coordinator.proposal.operation == .move, let sourceItem = coordinator.items.first?.dragItem.localObject as? YourDataType, let sourceIndexPath = collectionView.indexPath(forItem: sourceItem) else { return } // 更新数据源 yourDataSource.remove(at: sourceIndexPath.item) yourDataSource.insert(sourceItem, at: destIndexPath.item) // 批量更新UI collectionView.performBatchUpdates({ collectionView.moveItem(at: sourceIndexPath, to: destIndexPath) }) }
- 开启拖拽交互:
collectionView.dragDelegate = self collectionView.dropDelegate = self collectionView.dragInteractionEnabled = true
注意事项
- iOS16中
beginInteractiveMovementForItem的崩溃属于系统API已知问题,后续版本可能修复,建议关注系统更新 - 使用现代拖拽API时,需确保数据源与UI更新逻辑严格同步,避免数据不一致问题
内容的提问来源于stack exchange,提问作者Mousa AminSharifi
相关产品推荐
相关产品推荐

