Mihael Isaev Mihael Isaev - 3 months ago 18
iOS Question

Realm object property with getter/setter always return first stored value

I have a realm object:

class RMovements: Object {
dynamic var name: String!
dynamic var _quantity: Double = 0
var quantity: Double {
get {
return _quantity / 1000
}
set {
_quantity = newValue * 1000
}
}

override static func primaryKey() -> String? {
return "name"
}
}


After creating this object in realm store

do {
try realm.write({
let m = RMovements()
m.name = "john"
m.quantity = 2
realm.add(m, update: true)
})
} catch _ {}


In result I got

RMovements {
name = john;
_quantity = 2000;
quantity = 2;
}


Looks good! But now I want to change quantity to 9

do {
try realm.write({
let m = realm.objects(RMovements).filter("name=%@", "john").last!
m.quantity = 9
realm.add(m, update: true)
})
} catch _ {}


And here is surprise

RMovements {
name = john;
_quantity = 9000;
quantity = 2;
}


_quantity changed to 9000 properly, but quantity is still 2.
Why quantity still 2? It will always return first stored value and I don't understand why. Please help.

Demo project available on GitHub

Answer

What's happening here is that the quantity property isn't included in ignoredProperties() to let Realm know not to persist it, but it also isn't marked dynamic, which enables Realm to manage the property.

So it's in this in-between state that isn't supported. I suggest you mark the property as ignored:

class RMovements: Object {
    dynamic var name: String!
    dynamic var _quantity: Double = 0
    var quantity: Double {
        get {
            return _quantity / 1000
        }
        set {
            _quantity = newValue * 1000
        }
    }

    override static func primaryKey() -> String? {
        return "name"
    }

    override static func ignoredProperties() -> [String] {
        return ["quantity"]
    }
}

Note that Object's default description doesn't include ignored properties, so to print it, you'll need to override that:

override var description: String {
    return "RMovements {\n    name = \(name);\n    _quantity = \(_quantity);\n    quantity = \(quantity);\n}"
}

Then if I run your sample, I'll get the following log:

created
check: RMovements {
    name = john;
    _quantity = 2000.0;
    quantity = 2.0;
}
before update: RMovements {
    name = john;
    _quantity = 2000.0;
    quantity = 2.0;
}
after update: RMovements {
    name = john;
    _quantity = 9000.0;
    quantity = 9.0;
}
check: RMovements {
    name = john;
    _quantity = 9000.0;
    quantity = 9.0;
}