Search code examples
iosswiftuiimageviewuilabelxib

How to do initial styling of labels and UILabels/UIImageViews in a sub view which is loaded via an XIB in a UITableViewCell


I have a UITableViewCell which has a subview (inside its content view) which contains labels, and an image view and other properties I need to set.

This subview is set from an XIB as it is used elsewhere in the app. I am loading it into the cell with

private func setup() {
    let nib = UINib.init(nibName: "AuthorHeaderView", bundle: nil)
    if let view = nib.instantiate(withOwner: self, options: nil).first as? UIView {

        view.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(view)

        view.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        view.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        view.topAnchor.constraint(equalTo: topAnchor).isActive = true
        view.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }
}

Then, when the cell is loaded I am setting some default values in awakeFromNib(). When I have a breakpoint there, I can see that the headerView: AuthorHeaderView has been loaded into memory and is set up correctly, but it's labels and imageView haven't been, they are nil, and thus it crashes when trying to style these views.

How to do initial styling of labels and image views and everything in a sub view which is loaded via an XIB?


Solution

  • OK, so I found the solution out. The problem was that I hadn't added init(coder aDecoder: NSCoder)

    I have a setup method that was being called from awakeFromNib, but I also needed to call it from initWithCoder.

    Example:

    override func awakeFromNib() {
        super.awakeFromNib()
    
        setup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    
        setup()
    }
    
    private func setup() {
        let nib = UINib.init(nibName: "HeaderView", bundle: nil)
        if let view = nib.instantiate(withOwner: self, options: nil).first as? UIView {
    
            view.translatesAutoresizingMaskIntoConstraints = false
            self.addSubview(view)
    
            view.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
            view.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
            view.topAnchor.constraint(equalTo: topAnchor).isActive = true
            view.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        }
    }
    

    Anyway, now it works perfectly. Hope this helps someone else at some stage :-)