在进行重新排序时尝试在集合视图上开始重新排序

时间:2018-09-25 00:01:31

标签: ios swift uicollectionview

我在两个UICollectionView之间实现了拖放。有时我会收到这个奇怪的错误。

Assertion failure in -[UICollectionView _beginInteractiveMovementForItemAtIndexPath:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3698.54.4/UICollectionView.m:8459

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to begin reordering on collection view while reordering is already in progress'

我的设置如下,

  1. 我有两个UICollectionViews(例如A和B)
  2. 在两个集合视图中都启用了重新排序
  3. 将项目从A拖动到B时。操作为复制
  4. 将项目从B拖动到A时。该操作将从B中删除。A不会生效。

到目前为止,我的代码如下(抽象版)

// Drop delegate

    func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
    print(#function)
    let destinationIndexPath: IndexPath
    if let indexPath = coordinator.destinationIndexPath {
        destinationIndexPath = indexPath
        self.performDrop(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
    } else if collectionView.tag == CollectionView.timeline.rawValue {
        // Get last index path of collection view.
        let section = collectionView.numberOfSections - 1
        let row = collectionView.numberOfItems(inSection: section)
        destinationIndexPath = IndexPath(row: row, section: section)
        self.performDrop(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
    }
}

func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
    print(#function)
    if session.localDragSession != nil {
        // Trying to drag and drop an item within the app
        if collectionView.hasActiveDrag {
            // Trying to re-oder within the same collection view
            return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
        } else {
            // Trying to copy an item from another collection view
            return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
        }
    } else {
        // Trying to drag and drop an item from a different app
        return UICollectionViewDropProposal(operation: .forbidden)
    }
}

// Drag delegate

    func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
    print(#function)
    var item: Item?
    if collectionView.tag == CollectionView.media.rawValue {
        item = mediaItems[indexPath.row]
    } else {
        item = StoryManager.sharedInstance.timelineItems[indexPath.row]
    }

    if let item = item {
        let itemProvider = NSItemProvider(object: item.id as NSString)
        let dragItem = UIDragItem(itemProvider: itemProvider)
        dragItem.localObject = item
        return [dragItem]
    }
    return []
}

重制步骤

  1. 已实现上述两个委托方法的两个UICollectionViews
  2. 两者都应跨屏
  3. 从一个项目中拖动一个项目,并尝试在另一个项目的顶部按住并假装将其拖放到屏幕边缘
  4. 观察物品为新物品(待放物品)重新布置的余地
  5. 将手指滑离屏幕,观察它的显示效果,好像拖动已被取消。
  6. 请注意,重新布置的元素为新商品腾出了空间。如果您有用于集合视图的布局委托方法的控制台日志,您可能会发现它们不断被调用
  7. 现在,如果您尝试再次拖动一个项目或尝试摆脱屏幕应用程序崩溃的情况。

如果你们中的任何人对正在发生的事情有任何见识,那将有很大的帮助。

2 个答案:

答案 0 :(得分:1)

在启动新拖动时结束放置位置(UICollectionView)中的任何交互式移动都解决了我的问题。我必须按如下方式修改我的UICollectionViewDragDelegate方法,

    func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {

    var item: Item?
    if collectionView.tag == CollectionView.media.rawValue {
        item = mediaItems[indexPath.row]

// New line to fix the problem. 'timeline' is the IBOutlet of the UICollectionView I'm going to drop the item
        timeline.endInteractiveMovement()

    } else {
        item = StoryManager.sharedInstance.timelineItems[indexPath.row]

// New line to fix the problem. 'media' is the IBOutlet of the UICollectionView I'm going to drop the item
        media.endInteractiveMovement()

    }

    if let item = item {
        let itemProvider = NSItemProvider(object: item.id as NSString)
        let dragItem = UIDragItem(itemProvider: itemProvider)
        dragItem.localObject = item
        return [dragItem]
    }
    return []
}

要解决应用程序在导航时崩溃的问题,我必须结束viewWillDisappear中的所有交互式移动。

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

// 'media' and 'timeline' are the IBOutlets of the UICollectionViews I have implemented drag and drop
    timeline.endInteractiveMovement()
    media.endInteractiveMovement()
}

希望苹果会在将来的版本中修复此问题。

答案 1 :(得分:0)

看起来好像UICollectionViewDropDelegate的{​​{1}}方法在任何人进入该“问题”时都被调用。 我认为确保在此处“结束互动运动”要好很多:

dropSessionDidEnd