Can't set @IBInspectable computed property in

2019-07-12 19:56发布

I'm trying to add an IBInspectable color to UIView, so that I can set it in the storyboard and later use it in code. In this post regarding UITextField I've seen that I can take advantage of extensions and adding a computed property, but I can't make it work for UIView.

Identity inspector enter image description here

I get a crash: Failed to set (additionalColor1) user defined inspected property on (UIView): [ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key additionalColor1.

Any idea what's causing the crash and how to fix it?

Here's my code:

extension UIView {
    @IBInspectable var additionalColor1: UIColor? {
        return self.additionalColor1
    }
}

For the reference, I'm pasting the code that can be used to set the placeholder color for UITextField (same as the above url). This works ok:

extension UITextField {
    @IBInspectable var placeHolderColor: UIColor? {
        get {
            return self.placeHolderColor
        }
        set {
            self.attributedPlaceholder = NSAttributedString(string: self.placeholder != nil ? self.placeholder! : "", attributes:[NSForegroundColorAttributeName: newValue!])
        }
    }
}

2条回答
Animai°情兽
2楼-- · 2019-07-12 20:08

How is your additionalColor going to be used?

I had to do something similar to this recently, but in my case I was always applying the extra value right away.

For example, I wanted to create a button that looked like a parallelogram. So, I wanted a way to put in a value in the Storyboard, which would apply a CGAffineTransform. I'm not really storing the skew value, just using to change what the thing looks like. Then, in the get, I'm passing back the value from the view's affineTransform routine.

@IBInspectable var skewOffset: Float {
    set(newSkewOffset) {
        let affineTransform : CGAffineTransform = CGAffineTransform(a: 1.0, b: 0.0, c: CGFloat(newSkewOffset), d: 1.0, tx: 0.0, ty: 0.0)
        layer.setAffineTransform(affineTransform)
    }
    get {
        return Float(layer.affineTransform().c)
    }
}

So, I'm not storing skewOffset, I'm applying it, and I know how I can look it up later, if I need to get it.

查看更多
相关推荐>>
3楼-- · 2019-07-12 20:30

As mentioned in your question title

Swift extensions can only add computed properties to a type, but they cannot add stored properties.

(For more detailed information please refer to the Extension chapter in The Swift Programming Language.)

The example you posted is actually flawed — even if it has 50 upvotes on Stackoverflow at this time. If you return the value of a property itself from the property's getter you're creating a loop.

@IBInspectable var additionalColor1: UIColor? {
    return self.additionalColor1
}

If you have a view and you try to access view.additionalColor1 anywhere in your code your property's getter will be called which returns self.additionalColor1 — or with other words: it returns the property's value again — and guess how? By calling the propery's getter! (And so on...)

The example from the post you mentioned only "works" because the getter is evidently never called. It's only setting that computed property placeHolderColor that changes another stored property, namely the text field's attributedPlaceholder.

So while you can add computed properties to an existing class through an extension you can never think of it as a concrete value that's stored somewhere. Computed properties may only be used to somehow transform the value you assign to it and store the result in existing stored properties.

查看更多
登录 后发表回答