4

好的

我的拖放功能几乎可以完美运行。我长按一个单元格,它可以顺利地将按下的单元格移动到其他两个单元格之间的新位置。表格会调整,更改会保存到核心数据。伟大的!

坏的

我的问题是,如果我将单元格拖到表格底部单元格下方,即使我不放开(取消按下)单元格……应用程序也会崩溃。如果我慢慢拖动,当单元格穿过最后一个单元格的 y 中心时,它真的会崩溃……所以我认为这是与快照获取位置有关的问题。不太重要但可能相关的是,如果我在最后一个带有值的单元格下方长按,它也会崩溃。

拖放运行一个 switch 语句,该语句根据状态运行三组代码之一:

  • 新闻开始时的一种情况
  • 拖动单元格的一种情况
  • 当用户放开单元格时的一种情况

我的代码改编自本教程:

拖放教程

我的代码:

 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的不是零:

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

希望有帮助!

于 2015-08-31T06:05:12.880 回答
0

您没有说明崩溃发生在代码中的哪个位置,这使得确定发生了什么变得更加困难。在异常上设置断点以确定哪一行是罪魁祸首。为此,请使用 XCode 中断点列表左下角的“+”。

我认为主要问题是indexPath。有几个问题:

  1. 您正在使用 indexPath 即使它可能为零,在这一行:

    let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! CustomTableViewCell;
    
  2. indexPath 可能无效,即使它不是 nil。检查其部分和行成员是否与 NSNotFound 不同。

最后,我一直在使用一个预制的、开源的 UITableView 子类,它可以为你完成所有的移动,所以你不必再自己实现它了。它还负责自动滚动,您甚至还没有考虑过。直接使用它,或将其用作代码的灵感: https ://www.cocoacontrols.com/controls/fmmovetableview

于 2015-09-05T10:00:56.313 回答