LongPress GestureでUITableViewのsectionの間にCellを移動する実践

ネットでLongPressでUITableViewのCellを移動する文章がありますが、Sectionの間に移動する例はなかなか無いです。今日はその経験を共有しましょう。
##**実現する方法**##
1.長押した時、押した場所によって、該当Cellを取得し、IndexPathを変数originIndexPathに渡す。そして、綺麗な動き見えるためにスナップショットを作成して該当Cellを見えないように設定。
2.指が押しながら移動する時、スナップショットの座標Y軸を更新し、新しい位置のCellのIndexPathが元のIndexPathと違うとoriginIndexPathを更新し、データも更新。
3.リリースした時、該当Cellを見えるように設定して、スナップショットを削除。
**重要ポイント:**
移動の処理について、セクションが変わる場合、もしセクションの一番下から入る時、そのままIndexPathを変数originIndexPathに渡す前に、IndexPathに1行を追加することが必要。

##**画面操作**##
Main.storyboardの画面で、LibrayからLong Press Gesture Reconigerをドラグして、UITableVIewのCellの上に置きます。
##**コード**##
```Swift:UITableViewController
import UIKit
import CoreData

class CatalogViewController: UITableViewController{
    //CellのIndexPathを臨時保存用変数
    var originIndexPath: IndexPath?
　　//スナップショットの変数
    var initialSnapshot: UIView?
    //長押しジェスチャーの処理
    @IBAction func LongPress(_ sender: UILongPressGestureRecognizer) {
　　　　　//ジェスチャーの状態を取得
        let state = sender.state
　　　　　//指の位置を取得
        let location = sender.location(in: tableView)
　　　　　//指所在のCellのIndexPathを取得
        guard let indexPath = self.tableView.indexPathForRow(at: location) else { return }
        switch state {
　　　　　　　//最初押した時の処理
            case .began:
                    originIndexPath = indexPath
                    guard let cell = self.tableView.cellForRow(at: indexPath) else { return }
                    initialSnapshot = cellSnapshot(inputView: cell)
                    guard let snapshot = initialSnapshot else { return }
                    var center = cell.center
                    snapshot.center = center
                    snapshot.alpha = 0.0
                    self.tableView.addSubview(snapshot)
                    UIView.animate(withDuration: 0.25, animations: {
                        center.y = location.y
                        snapshot.center = center
                        snapshot.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)
                        snapshot.alpha = 0.98
                        cell.alpha = 0.0
                    }, completion:{(finished) in cell.isHidden = true })
　　　　　　　//指が移動する時の処理
            case .changed:
                guard let snapshot = initialSnapshot else { return }
                var center = snapshot.center
                center.y = location.y

                snapshot.center = center
                guard let sourceIndexPath = originIndexPath else { return }
                if indexPath.section != sourceIndexPath.section {
                   //IndexPathの更新   
　　　　　　　　　　  if indexPath.row + 1 == tableView.numberOfRows(inSection: indexPath.section){
                        originIndexPath = IndexPath(row: indexPath.row + 1, section: indexPath.section)
                        }else{ originIndexPath = indexPath }
　　　　　　　　　　　//データの更新、自身のプロジェクトによって修正が必要になります。
                  let cataitem = fetchedResultsController.object(at: sourceIndexPath )
                    cataitem.category = NSNumber(value: indexPath.section).boolValue
                        saveContext()
                }
　　　　　　　　　　//IndexPathの更新
                else if indexPath.row != sourceIndexPath.row {
                    tableView.moveRow(at: sourceIndexPath, to: indexPath)
                    originIndexPath = indexPath
                }
　　　　　　　//指が離れた時の処理
            default:
                guard let cell = self.tableView.cellForRow(at: originIndexPath!) else {return}
                guard let snapshot = initialSnapshot else {return}
                cell.isHidden = false
                cell.alpha = 0.0
                UIView.animate(withDuration: 0.25, animations: {
                    snapshot.center = cell.center
                    snapshot.transform = CGAffineTransform.identity
                    snapshot.alpha = 0
                    cell.alpha = 1
                }, completion: { (finished) -> Void in
                    if finished {
                        self.originIndexPath = nil
                        snapshot.removeFromSuperview()
                        self.initialSnapshot = nil
                    }})
        }
    }
    //スナップショットの作成関数
    private func cellSnapshot(inputView: UIView) -> UIView? {
        UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0)
        if let CurrentContext = UIGraphicsGetCurrentContext() {
            inputView.layer.render(in: CurrentContext)
        }
        guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        UIGraphicsEndImageContext()
        let snapshot = UIImageView(image: image)
        snapshot.layer.masksToBounds = false
        snapshot.layer.cornerRadius = 0
        snapshot.layer.shadowOffset = CGSize(width: -5, height: 0)
        snapshot.layer.shadowRadius = 5
        snapshot.layer.shadowOpacity = 0.4
        return snapshot
    }
```
以上です、Have fun!