Now that you know how to respond to cell-selection, let's have a look at a slightly more advanced topic – cell-deletion. Deleting data from a table view is a feature that many apps implement. If you have ever used the mail app on iOS, you might have noticed that several actions appear when a user swipes either right or left on a table-view cell. These swipe actions are a great feature to implement for Hello-Contacts so users can swipe over contacts and easily delete them. Of course, we won't be actually deleting contacts from a user's address book, but it would be possible to implement this if you truly wanted to.
In this example, you'll learn how to delete contacts from the array of contacts that is used to populate the table view. To implement support for cell-deletion, you need to implement another method from UITableViewDelegate. The method you need to implement is tableView(_:trailingSwipeActionsConfigurationForRowAt:). This delegate method is called when a user swipes over a table view cell and returns the actions should be shown when the cell moves sidewards. A good example of this is found in the mail app on iOS.
Add the following implementation of tableView(_:trailingSwipeActionsConfigurationForRowAt:) to the UITableViewDelegate extension for ViewController:
func tableView(_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
// 1
let deleteHandler: UIContextualActionHandler = { [weak self] action, view, callback in
self?.contacts.remove(at: indexPath.row)`
callback(true)
}
// 2
let deleteAction = UIContextualAction(style: .destructive,
title: "Delete", handler: deleteHandler)
// 3
return UISwipeActionsConfiguration(actions: [deleteAction])
}
If you run the app now and swipe from right to left over a table view cell, a delete button will appear from underneath the cell. In the code snippet, the first step is to set up a delete-handler that takes care of the actual deletion of the contact. This handler is a closure that is passed to the UIContextualAction instance that is created in step two. You have seen closures passed directly to method calls already, for instance as completion-handlers. However, you can also store a closure in a variable. This allows you to reuse your closure in several places and can make your code more readable. The third and last step is to create an instance on UISwipeActionsConfiguration and pass it the actions that you want to display. Since you can pass an array of actions, it is possible to show multiple actions when the user swipes over a cell. In this case, only a single action is added – the delete action.
Currently, tapping the delete button doesn't do much. While the contact is removed from the underlying data source, the table view itself doesn't update. Table views don't automatically stay in sync with their data sources. Add the following deleteHandler implementation to make sure the table view updates when the user taps the delete button:
let deleteHandler: UIContextualActionHandler = { [weak self] action, view, callback in
self?.contacts.remove(at: indexPath.row)
self?.tableView.beginUpdates()
self?.tableView.deleteRows(at: [indexPath], with: .fade)
self?.tableView.endUpdates()
callback(true)
}
This new version of deleteHandler ensures that the table view updates itself by removing the row that the user has decided to remove. Note that the contacts array is updated before updating the table view. When you update the table view like this, it will verify that it is in sync with the data source, which is the contacts array in this case. If the data source does not contain the expected amount of sections or rows, your app will crash. So whenever you update a table view, make sure to update the data source first. Also, note the calls to beginUpdates and endUpdates. These methods make sure that the table view doesn't reload in the middle of being manipulated. This is especially useful if you're performing a lot of complex updates, such as moving cells, inserting new ones, and removing old ones all at the same time.
With cell-deletion out of the way, let's have a look at reordering cells.