Search code examples
swiftuiviewibinspectable

Can't set @IBInspectable computed property in UIView


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!])
        }
    }
}

Solution

  • 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.