Denis Balko
Denis Balko

Reputation: 1596

Check if variable is computed or stored

In my app I translate objects from custom classes into dictionaries so that they can be saved locally in a plist as well as on a server. I use the following to turn the properties of a class into a dictionary:

func dictionary() -> [String : Any] {

    var count: UInt32 = 0;
    let myClass: AnyClass = self.classForCoder;
    let properties = class_copyPropertyList(myClass, &count);

    var dictionaryRepresentation: [String:Any] = [:]

    for i in 0..<count {
        let property = properties![Int(i)]
        let cStringKey = property_getName(property);
        let key = String(cString: cStringKey!)

        dictionaryRepresentation[key] = self.value(forKey: key) as Any
    }

    return dictionaryRepresentation
}

I have a problem, however, with computed properties. It seems that those are computed and the returned value gets put into the dictionary as well, which I would like to avoid. So here is my question:

Is it possible to check whether is a property computed programatically using only its name?

I am assuming this could be possible by trying to assign a value to it which would give me an error or some similar approach.

Upvotes: 2

Views: 582

Answers (2)

Denis Balko
Denis Balko

Reputation: 1596

Here is what seems to be a working solution, based on suggestion by dasblinkenlight.

Rather than using the Objective-C method outlined above, create a Mirror of the class which has a children made up of all settable properties, therefore excluding computables.

Used like this:

let mirror = Mirror(reflecting: MyObject)

for case let (label?, value) in mirror.children {
    print (label, value)
}

Here label is the name of the variable and value is obviously the value.

EDIT: In case anyone wants to convert objects into dictionary, I am posting the full code here as well. Do however remember that if values are custom objects as well, those will need to be converted too.

func dictionary() -> [String:Any] {
    let mirror = Mirror(reflecting: self)

    var dictionaryRepresentation = [String:Any]()

    for case let (label, value) in mirror.children {

        guard let key = label else { continue }

        dictionaryRepresentation[key] = value
    }

    return dictionaryRepresentation
}

Upvotes: 1

Vahan Babayan
Vahan Babayan

Reputation: 723

You can try property_copyAttributeList(_:_:) function, it may contain a read-only marker for swift's computed properties. Although I guess let properties also will have that marker, so you must find a way to differ them.

Upvotes: 0

Related Questions