Search code examples
iosswiftuicollectionviewuicollectionviewflowlayout

UICollectionView crash when moving items on iOS 16 beta


I have a UICollectionView in which user can long tap and then move the items. I have implemented func invalidationContext(forInteractivelyMovingItems and func invalidationContextForEndingInteractiveMovementOfItems methods to handle this.

While testing on iOS 16 beta, app crashes when move an item. Root cause is previousIndexPaths and targetIndexPaths both are become nil in below code. Any idea why this happens? On < iOS16 working fine.

open override func invalidationContext(forInteractivelyMovingItems targetIndexPaths: [IndexPath], withTargetPosition targetPosition: CGPoint, previousIndexPaths: [IndexPath], previousPosition: CGPoint) -> UICollectionViewLayoutInvalidationContext {
    
    let context = super.invalidationContext(forInteractivelyMovingItems: targetIndexPaths, withTargetPosition: targetPosition, previousIndexPaths: previousIndexPaths, previousPosition: previousPosition)
    
    //Check that the movement has actually happeneds
    if previousIndexPaths.first!.item != targetIndexPaths.first!.item {
        collectionView?.dataSource?.collectionView?(collectionView!, moveItemAt: previousIndexPaths.first!, to: targetIndexPaths.last!)
    }
    
    return context
}

open override func invalidationContextForEndingInteractiveMovementOfItems(toFinalIndexPaths indexPaths: [IndexPath], previousIndexPaths: [IndexPath], movementCancelled: Bool) -> UICollectionViewLayoutInvalidationContext {
    return super.invalidationContextForEndingInteractiveMovementOfItems(toFinalIndexPaths: indexPaths, previousIndexPaths: previousIndexPaths, movementCancelled: movementCancelled)
}

UICollectionView delegate method for moving item

func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {

    if self.longPressGesture.state == .ended {
        self.collectionView.reloadData()
        return
    }

    let cell = self.availableItems[sourceIndexPath.item]
    self.availableItems.remove(at: sourceIndexPath.item)
    self.availableItems.insert(cell, at: destinationIndexPath.item)
}

On iOS 16 previousIndexPaths and targetIndexPaths are nil enter image description here

On iOS 15 previousIndexPaths and targetIndexPaths are have values enter image description here


Solution

  • Simply by adding a delay it works for me now on iOS 16.

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
            }