I have a tableview which shows a list of objects called Requests. It has 3 segments. Namely Accepted, Received and Sent. And the objects for each segment are in 3 arrays.
I want to enable deleting rows (in turn the objects) only for Accepted and Sent segments.
This is my current implementation.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
var deleteAction: UIContextualAction?
switch currentShowingStatus {
case .accepted:
deleteAction = UIContextualAction(style: .destructive, title: "Delete") { action, view, completionHandler in
let request = self.acceptedRequests[indexPath.row]
completionHandler(true)
}
case .sent:
deleteAction = UIContextualAction(style: .destructive, title: "Delete") { action, view, completionHandler in
let request = self.sentRequests[indexPath.row]
completionHandler(true)
}
default:
break
}
if let deleteAction = deleteAction {
let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
configuration.performsFirstActionWithFullSwipe = false
return configuration
} else {
return UISwipeActionsConfiguration(actions: [])
}
}
As you can see there is quite a bit of duplicating code. And I can't extract away the UIContextualAction
declaration part because of it's completion handler. Selecting the object to be deleted happens in there.
I also can't define UISwipeActionsConfiguration
as a local variable and reduce its duplicating due to that class must be initialized with UIContextualAction
instances.
Note: You have to pass an empty actions array to UISwipeActionsConfiguration
in order to not show the swipe actions in cell. Returning nil
doesn't do it.
So all this has produced an ugly piece of code. I'm wondering if there's a better way to refactor this.
Alternative Approach
Instead of checking for segment first and then adding multiple delete actions, I put the checking for segment part inside one completion handler like this.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
var actions = [UIContextualAction]()
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { action, view, completionHandler in
switch self.currentShowingStatus {
case .accepted:
let request = self.acceptedRequests[indexPath.row]
self.deleteClientRequest(request)
case .sent:
let request = self.sentRequests[indexPath.row]
self.deleteClientRequest(request)
default:
break
}
completionHandler(true)
}
switch currentShowingStatus {
case .accepted, .sent:
actions.append(deleteAction)
case .received:
actions.removeAll()
}
let configuration = UISwipeActionsConfiguration(actions: actions)
configuration.performsFirstActionWithFullSwipe = false
return configuration
}
The downside is I still have to check for segment again in order to show the swipe action for just the Accepted and Sent segments.