Search code examples
swiftibinspectable

Swift @IBInspectables with priority choose the order are they executed in


I am playing a bit with @IBInspectables. I have created a reusable custom View which has some @IBInspectables.

Is there no way to give priority to the @IBInspectables to get executed?

In the following case to modify the color or the font of the placeholder Its needed to do through an attributed text. So I need that some @IBInspectables like Font, Color, get executed before the @IBInspectable which sets the placeholder text.

In this case I have done the workaround to get always the placeholder Color. However, I want to add more attributes to the placeholder like the Font but if I don't know which order are they going to get executed I would have to set the "attributedPlaceholder" from every IBInspectable that modifies the placeholder)

@IBInspectable
var placeholder: String? {
    didSet {
        guard let placeholder = placeholder else { return }

        textField.attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSAttributedStringKey.foregroundColor: placeholderColor ?? UIColor.red])
    }
}

@IBInspectable
var placeholderColor: UIColor? {
    didSet {
        guard let placeholderColor = placeholderColor else { return }

        textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder != nil ? textField.placeholder! : "", attributes: [NSAttributedStringKey.foregroundColor: placeholderColor])
    }
}

Solution

  • You should write the setters in a way that the order of calls won't matter. This is not only about the order of calls in Interface Builder, this is also about the order when called programatically.

    It shouldn't matter whether you call:

    view.placeholder = 
    view.placeholderColor = 
    

    or

    view.placeholderColor = 
    view.placeholder = 
    

    A sample implementation:

    @IBInspectable
    var placeholder: String? {
       didSet {
          updatePlaceholder()
       }
    }
    
    @IBInspectable
    var placeholderColor: UIColor? {
       didSet {
          updatePlaceholder()
       }
    }
    
    private func updatePlaceholder() {
       textField.attributedPlaceholder = NSAttributedString(
           string: placeholder ?? "",
           attributes: [.foregroundColor: placeholderColor ?? UIColor.red]
       )
    }