Search code examples
iosswiftrealm

Swift Realm exception


On my homeViewController I have a tableView with cells.
Cells are filled with data from Realm database.
Each cell can be deleted.
After deleting a cell everything is fine.
When I go to another viewController, and then go back again to Home, the app crashes, reason :

"Object has been deleted or invalidated."

Any ideas? Reload data and similar stuff doesn't help.
I am new in Realm stuff.

This is where I read my data from Realm to table

override func viewWillAppear(_ animated: Bool) {
    //tableView.reloadData()
    let realm = try! Realm()
    let result = realm.objects(CardsetTable.self)
    for r in result {
        self.cardsets.append(r)
    }
    for x in cardsets{
        self.titles.append(x)
    }
    self.tableView.reloadData()
}

And this is where I delete cell and Realm data :

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        let newSet = CardsetTable()
        newSet.cards = self.titles[indexPath.row].cards
        newSet.size = self.titles[indexPath.row].size
        newSet.title = self.titles[indexPath.row].title
        newSet.id = self.titles[indexPath.row].id
        let realm = try! Realm()
        try! realm.write {
            realm.delete(realm.objects(CardsetTable.self).filter("title=%@",titles[indexPath.row].title))
        }
        titles.remove(at: indexPath.row)
    }

    tableView.beginUpdates()
    tableView.deleteRows(at: [indexPath], with: .automatic)
    tableView.reloadData()
    tableView.endUpdates()
}

Solution

  • Couple of things to improve here. In the viewWillAppear, you are fetching the results from realm and doing the same again in your editingStyle: method which is unnecessary.

    let result = realm.objects(CardsetTable.self)
    

    You are adding the results to an array self.cardsets, which is not needed. You can use the result as an array and access its elements based on index.

    There is a possibility that you are unnecessarily adding realm elements in viewWillAppear, since viewWillAppear might get called many times, you need to take care of adding realm elements to an array as they get duplicated if you don't remove previous added elements.

    Coming to editingStyle method,

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            let newSet = CardsetTable()
            newSet.cards = self.titles[indexPath.row].cards
            newSet.size = self.titles[indexPath.row].size
            newSet.title = self.titles[indexPath.row].title
            newSet.id = self.titles[indexPath.row].id
            let realm = try! Realm()
            try! realm.write {
                realm.delete(realm.objects(CardsetTable.self).filter("title=%@",titles[indexPath.row].title))
            }
            titles.remove(at: indexPath.row)
        }
    
        tableView.beginUpdates()
        tableView.deleteRows(at: [indexPath], with: .automatic)
        tableView.reloadData()
        tableView.endUpdates()
    }
    

    I'm not actually sure why you create a new Realm object let newSet = CardsetTable() and don't use it.

    At this line :

    realm.delete(realm.objects(CardsetTable.self).filter("title=%@",titles[indexPath.row].title))
    

    you are re-fetching items from your realm db. This is also unnecessary. You could call the filter method on your prefetched realm array self.cardsets

    There are many possibilities for the error. It says the object you are trying to delete is already deleted or no longer valid.

    I see two possible reasons:

    1 - one of the realm object returned by realm.objects(CardsetTable.self) is already deleted

    2 - titles[indexPath.row] is returning a realm object, then accessing .title will cause error as titles[indexPath.row] already deleted from db.

    you can always validate the object is invalidated or not

      if (!rlmObj.isInvalidated){
            // delete
       }