web-dev-qa-db-ja.com

破壊的なスタイルのUIContextualActionは、デフォルトで行を削除するようです

私が見ている問題は、.destructiveand pass UIContextualActiontrueで作成するとcompletionHandlerが存在するように見えることです。行を削除するためのデフォルトのアクション。

Xcodeのテンプレートから新しいマスター/詳細アプリを作成し、このコードを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を使用しても行は削除されません。

.destructiveおよびtrueの結果、行はデフォルトで削除されます。

誰かがこの行動を説明できますか?行が削除されるのはなぜですか?

13
Murray Sagal

破壊的オプションのドキュメントによると:

データを削除したり、ある種の破壊的なタスクを実行したりするアクション。

完了は、アクションが成功したかどうかを示すことを意味します。 trueを渡すと、破壊的なタスクが成功したため、行を削除する必要があります。

破壊的なアクションが発生したときにdataSourceを手動で更新することを目的としており、そうしないとスクロールしてデータが再表示されます。また、データが削除されたことを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に行が削除されたことが通知されない限り、その後は1行ずつずれます。なんらかの方法で。

9
Kris Gellci

Kris Gellci の回答に同意しますが、NSFetchedResultsControllerを使用している場合は、事態が複雑になる可能性があることに注意してください。破壊的なUIContextualActionの場合、completion(true)を呼び出すと行が削除されるようですが、NSFetchedResultsControllerのデリゲートも削除される可能性があります。そのため、そのようにして簡単にエラーが発生する可能性があります。 NSFetchedResultsControllerを使用して、アクションが成功したかどうかに関係なく、completion(false)(コンテキストメニューを閉じるため)を呼び出すことにしました。次に、対応するオブジェクトが削除されました。

2
rene

この問題をiOS13で再現することはできません。iOS12以前の動作はバグであったか、単に取り下げられただけです(おそらく混乱したため)。

IOS 13では、何もせずにcompletion(true)を呼び出して.destructiveアクションから戻ると、何も起こらず、それで問題は終わりです。セルはnot削除されます。

1
matt