MohamMad Salah
MohamMad Salah

Reputation: 981

Object has been deleted or invalidated realm

I have this class inherit from Object:

class Location: Object {
    dynamic var id: String = ""
    dynamic var name: String = ""

    override class func primaryKey() -> String {
        return "id"
    }
}

This class is used as an instance inside my manager like this:

class LocationServiceAPI {

    fileprivate var _location: Location?
    var location: Location? {
        get {
            if _location == nil {
                let realm = try! Realm()
                _location = realm.objects(Location.self).first
            }
            return _location
        }
        set {
            let realm = try! Realm()

            if let newValue = newValue {
                // delete previous locations
                let locations = realm.objects(Location.self)
                try! realm.write {
                    realm.delete(locations)
                }

                // store new location
                try! realm.write {
                    realm.add(newValue, update: true)
                    _location = newValue
                }
            } else {
                let locations = realm.objects(Location.self)
                try! realm.write {
                    realm.delete(locations)
                }
            }
        }
    }
}

So whenever I get a location I delete the old one (new and old locations could be identical) and replace it with the new one, then I used the newValue as new value for the property _location but whenever I try to access the location it gives me 'Object has been deleted or invalidated'.

I am really confused since location will hold the value passed from the setter but not the realm!!

Note: If I stop the deleting then It will work fine.

Upvotes: 1

Views: 7035

Answers (2)

Bogdan Farca
Bogdan Farca

Reputation: 4096

Without knowing really anything about your app and your design choices, it looks like you're trying to avoid reading/writing to the DB too often by caching the location property. Unless you're working with tons of LocationServiceAPI objects it shouldn't be a real performance penalty to actually read/write directly in the DB, like this :

class LocationServiceAPI {

    var location: Location? {
        get {
            let realm = try! Realm()
            return realm.objects(Location.self).first
        }
        set {
           let realm = try! Realm()
           if let newValue = newValue {
              // store new location
              try! realm.write {
                  realm.add(newValue, update: true)
              }
           } else {
              // delete the record from Realm
              ...
           }
        }
    }
}

Also, I would in general avoid keeping Realm objects along for longer periods, I don't say it's not possible but in general it leads to issues like you've experienced (especially if do multi-threading). In most cases I'd rather fetch the object from DB, use it, change it and save it back in the DB asap. If keeping references to specific records in the DB is necessary I'd rather keep the id and re-fetch it when I need it.

Upvotes: 0

TiM
TiM

Reputation: 15991

The Object has been deleted or invalidated error will occur if an object has been deleted from a Realm, but you subsequently try and access a stored property of an instance of that object that your code was hanging onto since before the deletion.

You'll need to examine your logic paths and make sure there's no way you're deleting the location object, and not subsequently updating the _location property. There's no mention of deleting the object in the sample code you've provided, but your if let newValue = newValue line of code would mean that _location wouldn't actually get cleared if you passed in nil.

Finally, it's possible to manually check if an object has been deleted from a Realm by calling _location.invalidated, so if this happens a lot, it might be a good idea to include some extra checks in your code as well.

Upvotes: 1

Related Questions