Sweeper
Sweeper

Reputation: 273890

How can I use IBInspectable to control a property of a subview?

I am writing a custom view that has two labels as subviews - titleLabel and subtitleLabel.

I added two @IBInspectable properties called titleText and subtitleText so that I can set the texts of the labels very easily in the storyboard.

class MyView : UIView {
    var titleLabel: UILabel!
    var subtitleLabel: UILabel!

    @IBInspectable
    var titleText: String? {
        get { return titleLabel.text }
        set {
            titleLabel.text = newValue
            let fontSize = // calculates appropriate font size for the text...
            titleLabel.font = font.withSize(fontSize)
        }
    }

    @IBInspectable
    var subtitleText: String? {
        get { return subtitleLabel.text }
        set {
            subtitleLabel.text = newValue
            let fontSize = // calculates appropriate font size for the text...
            subtitleLabel.font = font.withSize(fontSize)
        }
    }

    override func draw(_ rect: CGRect) {
        // here I make the view look prettier, irrelevant to the question
    }
}

Now I need to initialise those two labels and add them as MyView's subviews. I thought I could do this in awakeFromNib:

override func awakeFromNib() {
    titleLabel = UILabel(frame: CGRect(
        x: ...,
        y: ...,
        width: ...,
        height: ...))
    self.addSubview(titleLabel)
    subtitleLabel = UILabel(frame: CGRect(
        x: ...,
        y: ...,
        width: ...,
        height: ...))
    self.addSubview(subtitleLabel)

}

So I added a MyView to the storyboard and set its properties with the properties inspector and I ran the app. It crashed.

Apparently, the IBInspectable properties are set before awakeFromNib so the labels have not been initialised by then.

This means that I need to initialise the labels in a method that is called before the IBInspectable properties are set.

What is a method that is called before IBInspectable properties are set that I can override to initialise the subviews?

Upvotes: 1

Views: 74

Answers (1)

Sulthan
Sulthan

Reputation: 130172

This might be obvious but the correct method to put such things into is the initializer.

// called when initialized from code
override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
}

// called when initialized from storyboard/xib
required init?(coder: NSCoder) {
    super.init(coder: coder)
    commonInit()
}

private func commonInit() {
   // add subviews
}

Also, there is no real reason for optionals in your specific case:

let titleLabel: UILabel = UILabel()

You can add the labels as subviews and update frames later.

Upvotes: 2

Related Questions