Uitableview 默认情况下,具有破坏性样式的UIContextualAction似乎会删除行

Uitableview 默认情况下,具有破坏性样式的UIContextualAction似乎会删除行,uitableview,swipe,ios11,Uitableview,Swipe,Ios11,我看到的问题是,当我在completionHandler中使用.destromical和passtrue创建UIContextualAction时,似乎有一个默认操作用于删除该行 如果您从Xcode的模板创建一个新的Master Detail应用程序,并将此代码添加到MasterViewController override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt ind

我看到的问题是,当我在
completionHandler
中使用
.destromical
pass
true
创建
UIContextualAction
时,似乎有一个默认操作用于删除该行

如果您从Xcode的模板创建一个新的Master Detail应用程序,并将此代码添加到
MasterViewController

override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let testAction = UIContextualAction(style: .destructive, title: "Test") { (_, _, completionHandler) in
        print("test")
        completionHandler(true)
    }
    return UISwipeActionsConfiguration(actions: [testAction])
}
您刷卡的行将被删除。请注意,这里没有更新表视图的代码。此外,模型不会更新,如果向上滚动导致行被重新加载,它将重新出现

在这种情况下传递
false
不会删除该行。或者使用
.normal
样式和
true
也不会删除该行

.destromical
true
默认情况下会删除该行


有人能解释这种行为吗?为什么要删除该行?

根据破坏性选项的文档:

删除数据或执行某种破坏性任务的操作

完成是为了表明行动是否成功。如果传递true,则意味着破坏性任务是成功的,因此应该删除该行

当破坏性操作发生时,您需要手动更新数据源,否则将导致滚动以使数据重新出现。您还需要告诉tableView数据已被删除

下面是一些显示工作示例的代码:

UIContextualAction(style: .destructive, title: "Delete") { [weak self] (_, _, completion) in
    if self?.canDelete(indexPath) { // We can actually delete
        // remove the object from the data source
        self?.myData.remove(at: indexPath.row)
        // delete the row.  Without deleting the row or reloading the
        // tableview, the index will be off in future swipes
        self?.tableView?.deleteRows(at: [indexPath], with: .none)
        // Let the action know it was a success.  In this case the 
        // tableview will animate the cell removal with the swipe
        completion(true)    
    } else { // We can't delete for some reason
        // This resets the swipe state and nothing is removed from
        // the screen visually.
        completion(false)
    }         
}
然后我需要重新加载
tableview
或调用
deleteRows
,以便在下次刷卡时正确计算
indexPath


如果我有10行,我刷第5行删除,之后的每一行都将被关闭一行,除非重新加载
tableview
,或者
tableview
以某种方式被告知该行已被删除。

我同意以下回答:,但是请注意,如果使用的是NSFetchedResultsController,则可能会使事情变得复杂。对于破坏性UIContextualAction,调用
completion(true)
似乎会删除该行,但NSFetchedResultsController的委托也会删除该行。因此,您很容易以这种方式结束错误。使用NSFetchedResultsController,我决定调用
完成(false)
(关闭上下文菜单),不管操作是否成功,然后让代理负责删除表行,如果相应的对象已被删除。

我无法在iOS 13中重现此问题。iOS 12及之前版本中的行为要么是一个bug,要么只是被撤销了(可能是因为它令人困惑)


在iOS 13中,如果您通过调用
completion(true)
破坏性
操作返回,而不做任何事情,则不会发生任何事情,这就是问题的结束。不会为您删除单元格。

使用下面的标志禁用完全滑动

使用完全滑动执行第一个操作

默认情况下,它将自动执行UISwipeActionsConfiguration中配置的第一个操作。因此,如果要禁用完全滑动删除,请将“performsFirstActionWithFullSwipe”设置为false

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let test = UIContextualAction(style: .destructive, title: "test") { (action, view, completion) in
        
        // Your Logic here
        completion(true)
    }
    
    let config = UISwipeActionsConfiguration(actions: [test])
    config.performsFirstActionWithFullSwipe = false
    return config
} 

希望这能解决您的问题。

按照此代码,我遇到了一个崩溃。原因是--您不应该自己删除此行self?.tableView?.deleteRows中的行(位于:[indexPath],带:.none)。当您调用completion(true)时,UIKit会删除行。的确,iOS12和iOS13的行为不同,我认为这是一个bug,