[Swift]UITableViewでDrag&Dropする際の注意点


はじめに

UITableViewでロングタップを使って並び替えをする際に、
上手く実装できずに時間を浪費してしまったので、参考になる方がいれば嬉しいです。

完成イメージ

UITableViewCellをロングタップするとDrag&Dropで並び替えができるようになります。

基本的な実装方法

詳しい実装方法自体は検索すれば見つかるので概要だけ記載します。
UITableViewにDrag&Dropできるように以下の設定をします。

ViewController.swift
tableView.dragInteractionEnabled = true
tableView.dragDelegate = self
tableView.dropDelegate = self

UITableViewDragDelegateの実装はこんな感じです。
Dragした際にセルの文字列を取得しています。

ViewController.swift
extension HomeViewController: UITableViewDragDelegate {
    func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
        let todoName = db.getItem(at: indexPath.row).text // Dragするセルの文字列を取得
        let todoProvider = NSItemProvider(object: todoName as NSItemProviderWriting)
        return [UIDragItem(itemProvider: todoProvider)]
    }
}

Dropした際に、tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator)が呼ばれて、
並び替えの実装をここでおこないます。

ViewController.swift
extension ViewController: UITableViewDropDelegate {
    func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
        return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
    }

    func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
        // Dropした際の並び替えの実装
    }
}

上手く実装できなかったところ

今回つまずいたところは、Dropした際にtableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator)の処理が呼ばれない問題でした。
他のfunc tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal
ちゃんと呼ばれることは堪忍できたので、UITableViewDropDelegateが設定できていないわけではないようです。

解決方法

ロングタップのDrag&Dropで並び替えをする前にnavigationItem.leftBarButtonItem = editButtonItemでUITabelViewの左上に編集ボタンを表示して、
並び替えをできるようにしており、こちらの機能を併用していると対象のメソッドが呼ばれなかったです。
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)などの並び替えするメソッドを削除したところ
ちゃんとtableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator)が呼ばれるました。

まとめ

簡単な実装からステップアップで機能を追加して行く際に、
似たような機能のイベントが影響することもままありそうなので気をつけたいところです。

参考記事

https://dev.classmethod.jp/articles/uitableview-dragdelegate-dropdelegate1/
https://developer.apple.com/documentation/uikit/drag_and_drop/adopting_drag_and_drop_in_a_table_view