Cannot create a custom view using Xib file due to nil subviews

Viewed 1366

I have a XIB file with 5 subviews. The XIB is set to a custom class like so

class Slide: UIView {

    @IBOutlet weak var descriptionImage: UIImageView!
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var hiLabel: UILabel!
    @IBOutlet weak var loLabel: UILabel!
    @IBOutlet weak var humidityLabel: UILabel!

}

I instantiate like so let slide = Slide()

When I try to set the variables ie slide.descriptionLabel = "Hello"

I get error

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

The stack trace shows that the XIB is instantiated, but the subviews are nil, and, therefore, cannot be set.

2 Answers

It's because you have to load the nib file ( here i suppose nib name is Slide )

let slide  = Bundle.main.loadNibNamed("Slide", owner: nil, options: nil)![0] as! Slide

as this

let slide = Slide()

loads the view without it's layout so all attached views are nil

When you are dealing with custom views, using Xibs, you should load them first.

So, for example, in your Slide class you can create a static function like:

static func createView(with owner: Any) -> Slide {
    let nib = UINib.init(nibName: "YourNibName", bundle: nil)
    let views = nib.instantiate(withOwner: owner, options: nil)
    let view = views[0] as! Slide
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}

where YourNibName should be the name of your Xib file.

This static function can be used like:

let slide = Slide.createView(with: self)

// attach the view to a superview
aSuperview.addSubview(slide)

// setup the right constraints
// for example
slide.topAnchor.constraint(equalTo: aSuperview.topAnchor).isActive = true
// ...and so on

The important bit is then to set in Interface Builder the right view for your Xib:

enter image description here

To recap your view should look like (note that I renamed Slide to SlideView. It sounds better to me):

class SlideView: UIView {
    @IBOutlet var descriptionImage: UIImageView!
    @IBOutlet var descriptionLabel: UILabel!
    @IBOutlet var hiLabel: UILabel!
    @IBOutlet var loLabel: UILabel!
    @IBOutlet var humidityLabel: UILabel!

    static func createView(with owner: Any) -> SlideView {
        let nib = UINib.init(nibName: "YourNibName", bundle: nil)
        let views = nib.instantiate(withOwner: owner, options: nil)
        let view = views[0] as! SlideView
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }
}
Related