In Swift, how can I use setValueForKey to set the

2019-08-23 06:33发布

问题:

Let's say we define an object like this:

let object: AnyObject = {

    var result = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 50))
    result.text = "First Text"
    result.backgroundColor = UIColor.blueColor()

    return result
}()

For this example, I explicitly created a UILabel, but in my actual project I don't know what type of object is created, so I'm just treating the result as AnyObject for this example. The object is just a standard UILabel with text of "First Text" on a blue background, default aligned to the left.

In this example case, I know that this object is actually a UILabel, so I know I can change it's properties like this:

(object as UILabel).text = "Second Text"

And now I've changed the text. But in my actual project, I don't know that my object is a UILabel, so I can't just do the (object as UILabel) trick, because it's not always a UILabel. My way around that is using setValueForKey. After checking that my object has a member called "text" using respondsToSelector (not shown in this example), I can change the text this way:

object.setValue("Third Text", forKey: "text")

Now, if I wanted to change the textAlignment of the object, after checking that the object does indeed have a member called textAlignment, I'd want to do something like this:

object.setValue(NSTextAlignment.Center, forKey: "textAlignment")

Doing this results in an error though:

Type 'NSTextAlignment' does not conform to protocol 'AnyObject'

I ran into something similar while trying this approach with setting the frame, because it didn't like the CGRect type, but I was able to get around it by converting the CGRect to an NSValue. However, I can't find a way to fix it for enum types like NSTextAlignment.

Anybody know how I can achieve my goal here?

回答1:

You have to use raw value NSTextAlignment.Center.rawValue

 object.setValue(NSTextAlignment.Center.rawValue, forKey: "textAlignment")


回答2:

Another option would be to declare a protocol with the properties you are interested in, and then extend the types you want to work with to adopt that protocol. IF that would work for you in this case, it seems safer.