4

いいもの

私のドラッグ&ドロップ機能は、ほとんど素晴らしく機能します。セルを長押しすると、押したセルを他の 2 つのセル間の新しい場所にスムーズに移動できます。テーブルが調整され、変更がコア データに保存されます。すごい!

悪い人

私の問題は、テーブルの一番下のセルの下にセルをドラッグすると、セルを離さない (押しない) 場合でも、アプリがクラッシュすることです。ドラッグをゆっくり行うと、セルが最後のセルの y 中心を横切るときに実際にクラッシュします...そのため、スナップショットが場所を取得することに関連する問題だと思います。それほど重要ではありませんが、関連している可能性があるのは、値が含まれている最後のセルの下を長押しすると、それもクラッシュすることです。

ドラッグ アンド ドロップは、ステータスに基づいて 3 つのコード セットのいずれかを実行する switch ステートメントから実行されます。

  • 報道が始まる一例
  • セルがドラッグされている場合の 1 つのケース
  • ユーザーがセルから手を離したときの 1 つのケース

私のコードはこのチュートリアルから適応されています:

ドラッグ & ドロップのチュートリアル

私のコード:

 func longPressGestureRecognized(gestureRecognizer: UIGestureRecognizer) {

    let longPress = gestureRecognizer as! UILongPressGestureRecognizer
    let state = longPress.state

    var locationInView = longPress.locationInView(tableView)
    var indexPath = tableView.indexPathForRowAtPoint(locationInView)

    struct My {
        static var cellSnapshot : UIView? = nil
    }
    struct Path {
        static var initialIndexPath : NSIndexPath? = nil
    }

    let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! CustomTableViewCell;

    var dragCellName = currentCell.nameLabel!.text
    var dragCellDesc = currentCell.descLabel.text


    //Steps to take a cell snapshot. Function to be called in switch statement
    func snapshotOfCell(inputView: UIView) -> UIView {
        UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0.0)
        inputView.layer.renderInContext(UIGraphicsGetCurrentContext())
        let image = UIGraphicsGetImageFromCurrentImageContext() as UIImage
        UIGraphicsEndImageContext()
        let cellSnapshot : UIView = UIImageView(image: image)
        cellSnapshot.layer.masksToBounds = false
        cellSnapshot.layer.cornerRadius = 0.0
        cellSnapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0)
        cellSnapshot.layer.shadowRadius = 5.0
        cellSnapshot.layer.shadowOpacity = 0.4
        return cellSnapshot
    }


    switch state {
        case UIGestureRecognizerState.Began:
            //Calls above function to take snapshot of held cell, animate pop out
            //Run when a long-press gesture begins on a cell
            if indexPath != nil && indexPath != nil {
                Path.initialIndexPath = indexPath
                let cell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!
                My.cellSnapshot  = snapshotOfCell(cell)
                var center = cell.center

                My.cellSnapshot!.center = center
                My.cellSnapshot!.alpha = 0.0

                tableView.addSubview(My.cellSnapshot!)

                UIView.animateWithDuration(0.25, animations: { () -> Void in
                    center.y = locationInView.y

                    My.cellSnapshot!.center = center
                    My.cellSnapshot!.transform = CGAffineTransformMakeScale(1.05, 1.05)
                    My.cellSnapshot!.alpha = 0.98

                    cell.alpha = 0.0

                    }, completion: { (finished) -> Void in

                        if finished {
                            cell.hidden = true
                        }
                })
            }
        case UIGestureRecognizerState.Changed:

            if My.cellSnapshot != nil && indexPath != nil {
                //Runs when the user "lets go" of the cell
                //Sets CG Y-Coordinate of snapshot cell to center of current location in table (snaps into place)
                var center = My.cellSnapshot!.center
                center.y = locationInView.y
                My.cellSnapshot!.center = center

                var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
                var context: NSManagedObjectContext = appDel.managedObjectContext!
                var fetchRequest = NSFetchRequest(entityName: currentListEntity)
                let sortDescriptor = NSSortDescriptor(key: "displayOrder", ascending: true )
                fetchRequest.sortDescriptors = [ sortDescriptor ]


                //If the indexPath is not 0 AND is not the same as it began (didn't move)...
                //Update array and table row order
                if ((indexPath != nil) && (indexPath != Path.initialIndexPath)) {

                    swap(&taskList_Cntxt[indexPath!.row], &taskList_Cntxt[Path.initialIndexPath!.row])
                    tableView.moveRowAtIndexPath(Path.initialIndexPath!, toIndexPath: indexPath!)

                    toolBox.updateDisplayOrder()
                    context.save(nil)

                    Path.initialIndexPath = indexPath
                }
            }
        default:
            if My.cellSnapshot != nil && indexPath != nil {
                //Runs continuously while a long press is recognized (I think)
                //Animates cell movement
                //Completion block: 
                //Removes snapshot of cell, cleans everything up
                let cell = tableView.cellForRowAtIndexPath(Path.initialIndexPath!) as UITableViewCell!

                cell.hidden = false
                cell.alpha = 0.0
                UIView.animateWithDuration(0.25, animations: { () -> Void in
                    My.cellSnapshot!.center = cell.center
                    My.cellSnapshot!.transform = CGAffineTransformIdentity
                    My.cellSnapshot!.alpha = 0.0
                    cell.alpha = 1.0
                    }, completion: { (finished) -> Void in
                        if finished {
                            Path.initialIndexPath = nil
                            My.cellSnapshot!.removeFromSuperview()
                            My.cellSnapshot = nil
                        }
                })//End of competion block & end of animation

            }//End of 'if nil'

    }//End of switch

}//End of longPressGestureRecognized

潜在的な犯人

私の推測では、この問題は、セルが最後のセルの下にあると座標を取得できないことに関連していると思われます。実際には浮遊しているわけではなく、他のセルとの関係で常に位置を設定しています。解決策は、場所を参照するセルがない場合に魔法のようなことをする if ステートメントになると思います。しかし、何!?! 各ケースに nil チェックを追加しても、何らかの理由で機能しません。

明確な質問

クラッシュを回避し、ドラッグしたセルが最後のセルの下にドラッグされるイベントを処理するにはどうすればよいですか?

クラッシュのスクリーンショット:

範囲外

4

2 に答える 2

3

ぶさいく

indexPathあなたがnilでないことを確認するために、単に先制チェックを行う必要があるようです:

var indexPath = tableView.indexPathForRowAtPoint(locationInView)
if (indexPath != nil) {
    //Move your code to this block
}

それが役立つことを願っています!

于 2015-08-31T06:05:12.880 に答える
0

コードのどこでクラッシュが発生したかを述べていないため、何が起こっているのかを判断するのが難しくなっています。例外にブレークポイントを設定して、原因となっている行を特定します。これを行うには、XCode のブレークポイント リストの左下隅にある「+」を使用します。

私が思う主な問題は、indexPath にあります。いくつかの問題があります。

  1. 次の行では、nil の可能性がありますが、indexPath を使用しています。

    let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! CustomTableViewCell;
    
  2. nil でなくても、indexPath は無効になる可能性があります。そのセクションと行のメンバーが NSNotFound と異なることを確認します。

最後に、事前に作成されたオープン ソースの UITableView サブクラスを使用してすべての移動を行うので、もう自分で実装する必要はありません。また、まだ考慮していない自動スクロールも処理します。直接使用するか、コードのインスピレーションとして使用してください: https://www.cocoacontrols.com/controls/fmmovetableview

于 2015-09-05T10:00:56.313 に答える