Can I set values for a Swift object properties using mirroring?
Asked Answered
K

2

11

Right now I can inspect variables of an object using Mirror type. But can I set values for my variables using mirroring? Or maybe there's another pure-Swift way?

For example, I'd like to create an object (a Swift struct) from JSON. Is it possible without subclassing NSObject and using Objective-C functions for that?

Killerdiller answered 30/9, 2015 at 23:11 Comment(0)
T
5

This was the best I can do at the moment. It is still missing converting the mirrorObject back to its generic type. FYI this is using SwiftyJSON

func convertToObject<T>(json: JSON, genericObject: T) -> T {
    let mirroredObject = Mirror(reflecting: genericObject)

    for (_, var attr) in mirroredObject.children.enumerate() {
        if let propertyName = attr.label as String! {
            attr.value = json[propertyName]
            print(propertyName)
            print(attr.value)
        }
    }
    // Figure out how to convert back to object type...
}
Typeset answered 16/10, 2015 at 4:45 Comment(3)
@Killerdiller It's the Figure out how to convert back to object type part that is the hard part. Unless you want to make custom extension for every type you ever create. In swift 4 there is Decodable and Encodable. These can do this dynamically.Judaic
This just errors: Value of type 'Mirror.Children' (aka 'AnyCollection<(label: Optional<String>, value: Any)>') has no member 'enumerate'Hardspun
If you make it enumerated it works, but setting the attr.value has no effect on the object property valueHardspun
P
4

This is an old question, but the answer was not working for me.

I had to change my swift object to a NSObject to make things work, and also to have dynamic properties.

In my case I use the pod Marshal to deserialize Data.

 class MyClass: NSObject, Unmarshaling
  {
       // @objc dynamic make property available for NSObject
       @objc dynamic var myProperty: String?

       required init(object: MarshaledObject) throws {
          super.init()

          initUsingReflection(object: object)
        }

        func initUsingReflection(object: MarshaledObject) {
          let mirror = Mirror(reflecting: self)

          // we go through children
          for child in mirror.children {
            guard let key = child.label else {
              continue
            }

            // This line is here to get the value from json, in my case I already know the type I needed
            let myValue: String = try! object.value(for: key)

            // The trick is here, setValue only exist in NSObject and not in swift object.
            self.setValue(myValue, forKey: key)
          }
       }
  }
Patrick answered 19/12, 2017 at 18:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.