iOS10下UICollectionView拖拽重排崩溃,iOS11正常问题求助
iOS10 UICollectionView拖拽重排崩溃问题解决
我帮你梳理下这个问题的核心原因和修复方案——你遇到的崩溃大概率是iOS10与iOS11的UICollectionView重排API差异导致的,毕竟两套系统的实现逻辑有不小区别:
核心问题分析
iOS10确实引入了UICollectionView的交互式重排,但它用的是一套旧API,和iOS11+推出的拖拽Drop框架完全是两回事:
- iOS10依赖
beginInteractiveMovementForItemAtIndexPath:这类方法,且必须配合UICollectionViewFlowLayout(或其子类)使用 - iOS11+新增了
UICollectionViewDragDelegate/UICollectionViewDropDelegate,功能更强大但iOS10完全不兼容
如果你的代码里混用了两套API,或者没针对iOS10做适配,就会触发崩溃。
修复步骤
1. 先确保数据源方法正确实现
iOS10的重排要求必须实现这两个UICollectionViewDataSource方法,缺一不可:
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath { // 返回YES允许该单元格被拖拽 return YES; } - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { // 一定要同步更新你的数据源数组,否则UI和数据会脱节 id item = self.dataArray[sourceIndexPath.item]; [self.dataArray removeObjectAtIndex:sourceIndexPath.item]; [self.dataArray insertObject:item atIndex:destinationIndexPath.item]; }
2. 修正你的Pan手势处理逻辑
你的addCollectionViewGestureRecognizers方法创建了Pan手势,但手势的回调方法需要严格适配iOS10的API,还要避免调用iOS11+才有的接口:
- (void)handlePanGesture:(UIPanGestureRecognizer *)gesture { CGPoint touchLocation = [gesture locationInView:self.collectionView]; NSIndexPath *tappedIndexPath = [self.collectionView indexPathForItemAtPoint:touchLocation]; switch (gesture.state) { case UIGestureRecognizerStateBegan: // 只有当indexPath有效且允许移动时,才启动交互 if (tappedIndexPath && [self.collectionView.dataSource collectionView:self.collectionView canMoveItemAtIndexPath:tappedIndexPath]) { if (@available(iOS 10.0, *)) { [self.collectionView beginInteractiveMovementForItemAtIndexPath:tappedIndexPath]; } } break; case UIGestureRecognizerStateChanged: if (@available(iOS 10.0, *)) { [self.collectionView updateInteractiveMovementTargetPosition:touchLocation]; } break; case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: if (@available(iOS 10.0, *)) { [self.collectionView endInteractiveMovement]; } break; default: if (@available(iOS 10.0, *)) { [self.collectionView cancelInteractiveMovement]; } break; } }
3. 关键注意事项
- 必须用FlowLayout:iOS10的
beginInteractiveMovementForItemAtIndexPath:只支持UICollectionViewFlowLayout或它的子类,如果是自定义Layout,你需要自己实现targetIndexPathForInteractivelyMovingItem:withPosition:等方法,否则会直接崩溃。 - 隔离iOS11+的API:如果你的代码里同时实现了iOS11的拖拽代理方法,一定要用
@available(iOS 11.0, *)包裹,避免iOS10调用到不存在的方法。 - 查看崩溃日志:如果还是崩溃,先看具体报错——如果是
unrecognized selector sent to instance,那肯定是调用了iOS10没有的API,针对性加版本判断即可。
版本适配优化(可选)
如果要同时兼容iOS10和iOS11+,可以做分支处理:
// 在viewDidLoad中 if (@available(iOS 11.0, *)) { self.collectionView.dragDelegate = self; self.collectionView.dropDelegate = self; self.collectionView.dragInteractionEnabled = YES; } else { [self addCollectionViewGestureRecognizers]; // 你的iOS10手势添加方法 }
内容的提问来源于stack exchange,提问作者RemembranceNN
相关产品推荐
相关产品推荐

