Row in UITableView isn't deleted immediately

424 Views Asked by At

I'm using trailingSwipeActionsConfigurationForRowAt UITableView's delegate method for handling when user swipe to delete certain cell (item).

My UIContextualAction for delete event looks like this. I first remove item from Realm database and then I delete row from my table view

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let deleteAction = UIContextualAction(style: .destructive, title: nil) { _,_,_ in
        Repository.shared.deleteItem(self.items![indexPath.row])
        tableView.deleteRows(at: [indexPath], with: .fade)
    }
    ...
}

But from some reason when I delete cell, it isn't deleted immediately and it returns to position between swipe. Then when I scroll table view, cell disappeared like you can see in gif below:

enter image description here

I can "fix" this by reloading data of table view right after I remove certain item from database, but this is not what I want to, I want to use deleteRow(at:with:) because of animation.


One my guess is, that it has something to do with deleting item from Realm database.

I'm deleting item using delete method

func deleteItem(_ item: Item) {
    do {
        try realm.write {
            realm.delete(item)
        }
    } catch {
        print(error)
    }
}

then as data source array for my table view I'm using Realm's Results

var items: Results<Item>?

Does anybody have any idea why this happens? Thank you.

1

There are 1 best solutions below

0
Daniel Hu On

I was facing the exactly the issue you had. I'm using Realm too, and I also used Results<Item> as my tableView datasource.

My implementation for swipe-to-delete-cell in tableView(_:, trailingSwipeActionsConfigurationForRowAt:) method is exactly same as yours: delete the swiped item in realm.write{} block, then call UITableView.deleteRows(at:with:) method to update the tableView. There's no need to update the datasource items as Realm Results<T> auto updates itself.

All is working well on iOS 13 and above, but when I tested it on iOS 12.4, iPhone 6 simulator, I had the same issue as you described in the question.

I figured out a solution while reading this article, it turned out that all you need to do is to call the completion handler provided in UIContextualAction.Handler after you have finished your updates, please refer to the code below:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { _, _, completion in
        Repository.shared.deleteItem(self.items![indexPath.row])  // delete item from Realm
        tableView.deleteRows(at: [indexPath], with: .fade)  // update tableView
        completion(true) // notify the tableView that the swipe action has completed so now it can perform UI updates (this line is no longer needed on iOS 13+)
    }
    ...
}

This solved my problem, hope it works for you too.