chrishale
chrishale

Reputation: 2526

Dynamically set properties from Dictionary<String, Any?> in Swift

I'm trying to set some properties on a class based on the values in a dictionary, at present I'm doing this:

let view: UIView = UIView()

if let hidden: Bool = self.props["hidden"] as? Bool {
  view.hidden = hidden
}

if let frame: CGRect = self.props["frame"] as? CGRect {
  self.uiInstance?.frame = frame
}

if let backgroundColor: UIColor = self.props["backgroundColor"] as? UIColor {
  self.uiInstance?.backgroundColor = backgroundColor
}

Which is fine with a few properties, but tiresome when it comes to large amounts. Is it possible in swift to do something like:

var view: UIView = UIView()

let config: Dictionary<String, Any?> = ["frame": CGRectZero, "backgroundColor": UIColor.whiteColor()]

for (key, value) in config {
  // view.??? = value
}

I'm aware there are could be risks of an error, if the config dictionary had something that didn't match an attribute on the UIView instance. e.g. ["text": "this is not going to work"]. But aside from that, is it possible to dynamically set attributes on a class (like you can with some other languages, e.g. ruby's send - http://ruby-doc.org/core-2.1.5/Object.html#method-i-send

Upvotes: 2

Views: 2130

Answers (1)

Martin R
Martin R

Reputation: 540005

This is possible with the NSKeyValueCoding method setValuesForKeysWithDictionary which calls setValue:forKey: for each key-value pair in the dictionary:

let config: [String : AnyObject] = [
    "frame": NSValue(CGRect: CGRectZero),
    "hidden" : true,
    "backgroundColor": UIColor.whiteColor(),
    "autoresizingMask" : UIViewAutoresizing.FlexibleHeight.rawValue
]
self.view.setValuesForKeysWithDictionary(config)

But note that all values must be Objective-C objects, which is why the frame is wrapped into an NSValue object. More about struct and scalar support in Key-Value Coding can be found here.

Some types (such as Bool, Int) are automatically bridged to NSNumber, therefore the true value for the hidden attribute needs not to be wrapped. "options" such as UIViewAutoresizing must be converted to the underlying integer value (which is then bridged to NSNumber automatically).

Upvotes: 6

Related Questions