Swift
UIView
XIB
iOS Development
Custom Class

How to initialize/instantiate a custom UIView class with a XIB file in Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A common UIKit pattern is to keep a reusable UIView subclass in Swift while describing its layout in a XIB file. The reliable approach is to load the nib in a shared initializer, attach the nib's content view to the custom view, and make sure both code-based and storyboard-based creation paths call the same setup logic.

Use a Shared Initializer

Your custom view can be created through init(frame:) or init(coder:), so both paths should call one common setup method.

swift
1import UIKit
2
3final class ProfileCardView: UIView {
4    @IBOutlet private weak var titleLabel: UILabel!
5    @IBOutlet private weak var subtitleLabel: UILabel!
6    @IBOutlet private var contentView: UIView!
7
8    override init(frame: CGRect) {
9        super.init(frame: frame)
10        commonInit()
11    }
12
13    required init?(coder: NSCoder) {
14        super.init(coder: coder)
15        commonInit()
16    }
17
18    private func commonInit() {
19        Bundle.main.loadNibNamed("ProfileCardView", owner: self, options: nil)
20        addSubview(contentView)
21        contentView.frame = bounds
22        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
23    }
24
25    func configure(title: String, subtitle: String) {
26        titleLabel.text = title
27        subtitleLabel.text = subtitle
28    }
29}

This pattern supports both programmatic and Interface Builder instantiation.

Configure the XIB Correctly

For the File's Owner pattern, the important setup in Interface Builder is:

  • set File's Owner to the custom view class
  • connect outlets from File's Owner to controls and the root contentView
  • keep the root visual object as a plain UIView

If that wiring is wrong, the nib may load but the outlets will be nil or the layout will not attach correctly.

Use Constraints Instead of Frames When Needed

Autoresizing masks are enough for simple layouts, but Auto Layout is often more reliable for reusable components.

swift
1private func commonInit() {
2    Bundle.main.loadNibNamed("ProfileCardView", owner: self, options: nil)
3    addSubview(contentView)
4    contentView.translatesAutoresizingMaskIntoConstraints = false
5    NSLayoutConstraint.activate([
6        contentView.topAnchor.constraint(equalTo: topAnchor),
7        contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
8        contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
9        contentView.trailingAnchor.constraint(equalTo: trailingAnchor)
10    ])
11}

Pinning the loaded view to all edges avoids sizing bugs when the parent view changes later.

A Factory Method Is Another Option

If the XIB root view itself is the custom class instead of using File's Owner, a factory method can be a clean instantiation style.

swift
1import UIKit
2
3extension ProfileCardView {
4    static func instantiate() -> ProfileCardView {
5        let nib = UINib(nibName: "ProfileCardView", bundle: nil)
6        guard let view = nib.instantiate(withOwner: nil, options: nil).first as? ProfileCardView else {
7            fatalError("ProfileCardView.xib is not configured correctly")
8        }
9        return view
10    }
11}

Both patterns are valid, but mixing them in the same component usually creates confusion.

Use the View Like Any Other UIKit Component

Once the nib loading is encapsulated, the custom view becomes easy to reuse.

swift
let card = ProfileCardView(frame: CGRect(x: 20, y: 40, width: 280, height: 120))
card.configure(title: "Ava", subtitle: "iOS Engineer")
view.addSubview(card)

That is the main benefit of the pattern: the rest of the app does not need to care that the layout came from a XIB.

Common Pitfalls

A common mistake is loading the nib in only one initializer. The view then works in one creation path and fails in the other.

Another is mixing the File's Owner pattern with a root view that is also set to the custom class. That often causes outlet confusion.

Developers also sometimes use Bundle.main for code that will later move into a framework, where the nib actually lives in a different bundle.

Summary

  • Load the XIB from a shared initializer called by both UIKit init paths.
  • Attach the loaded content view to the custom UIView and pin it correctly.
  • Choose either the File's Owner pattern or the root-view-as-custom-class pattern and stay consistent.
  • Encapsulate nib loading so the rest of the app can treat the view like a normal UIKit component.

Course illustration
Course illustration