Reputation: 981
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
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
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