Swift 撤消功能,先前声明的变量始终为空

Swift undo feature, previously declared variable is always empty

我正在尝试在删除 UITableView 中的单元格时实现撤消功能。要删除的单元格数据被声明为变量。删除部分工作正常,但是当我尝试 'undo' 删除时,变量始终为空。

实施

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let delete = UITableViewRowAction(style: UITableViewRowAction.Style.destructive, title: "Delete") { (action, indexPath) in

        let selectedExercise = self.exercises[indexPath.row] 
        //selectedExercise is declared here to be used in both 
        //`deleteExercise` and `undoDeleteExercise`

        self.undoManager?.registerUndo(withTarget: self, handler: { (selfTarget) in
            self.undoDeleteExercise(indexPath: indexPath, selectedExercise: selectedExercise)
        })

        self.deleteExercise(indexPath: indexPath, selectedExercise: selectedExercise)

        let message = MDCSnackbarMessage()
        message.text =  "Removing Exercise"
        let action = MDCSnackbarMessageAction()

        action.handler =  {() in
            self.undoManager?.undo()
        }
        action.title = "UNDO"
        message.action = action
        MDCSnackbarManager.show(message)
    }
    return [delete]
}

正在删除 这按预期工作。所选练习将从数据库、练习数组和 tableView.

中删除
func deleteExercise(indexPath: IndexPath, selectedExercise: Exercise){
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let managedContext = appDelegate.persistentContainer.viewContext

    let _ : NSError! = nil
    do {
        managedContext.delete(selectedExercise as NSManagedObject)
        exercises.remove(at: indexPath.row)
        self.execisesTableView.deleteRows(at: [indexPath], with: .automatic)
        try managedContext.save()
    } catch {
        print("error : \(error)")
    }

    ifNoExercises()
}

撤消删除 这里的问题是 selectedExercise 始终是一个空对象,因此尽管该行已添加到数据库中并且 tableView 它不包含任何信息。

func undoDeleteExercise(indexPath: IndexPath, selectedExercise: Exercise){
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let managedContext = appDelegate.persistentContainer.viewContext

    let _ : NSError! = nil
    do {
        managedContext.insert(selectedExercise as NSManagedObject)

        exercises.insert(selectedExercise, at: indexPath.row)
        execisesTableView.insertRows(at: [indexPath], with: .automatic)
        try managedContext.save()
    } catch {
        print("error : \(error)")
    }

    ifNoExercises()
}

对于遇到同样问题的任何人,这就是我解决的方法(这取代了 editActionsForRowAt):

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let contextItem = UIContextualAction(style: .destructive, title: "Delete") {  (contextualAction, view, boolValue) in
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext

        let exerciseEntity = NSEntityDescription.entity(forEntityName: MyVariables.exerciseEntity, in: managedContext)!

        let copiedExercise = NSManagedObject(entity: exerciseEntity, insertInto: managedContext)

        let selectedExercise = self.exercises[indexPath.row]

        copiedExercise.setValue(selectedExercise.distance, forKeyPath: MyVariables.distance)
        copiedExercise.setValue(selectedExercise.end_time, forKeyPath: MyVariables.endTime)
        copiedExercise.setValue(selectedExercise.lat_lngs, forKeyPath: MyVariables.latLngs)
        copiedExercise.setValue(selectedExercise.map_string, forKeyPath: MyVariables.mapString)
        copiedExercise.setValue(selectedExercise.start_time, forKeyPath: MyVariables.startTime)

        self.undoManager?.registerUndo(withTarget: self, handler: { (selfTarget) in
            self.undoDeleteExercise(indexPath: indexPath, selectedExercise: copiedExercise as! Exercise)
        })

        self.deleteExercise(indexPath: indexPath, selectedExercise: selectedExercise)

        let message = MDCSnackbarMessage()
        message.text =  "Removing Exercise"
        let action = MDCSnackbarMessageAction()

        action.handler =  {() in
            self.undoManager?.undo()
        }
        action.title = "UNDO"
        message.action = action
        MDCSnackbarManager.show(message)
    }
    let swipeActions = UISwipeActionsConfiguration(actions: [contextItem])

    return swipeActions
}