iOS development
Swift programming
Interface Builder
custom view creation
Xcode tips

How do I create a custom iOS view class and instantiate multiple copies of it in IB?

Master System Design with Codemia

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

Introduction

The usual way to create reusable custom views in iOS is to subclass UIView, give the class a small public API, and assign that class to multiple UIView instances in Interface Builder. If the view has nontrivial internal layout, load a companion XIB from inside the class so every instance shares the same structure.

The Two Reuse Patterns

There are two common patterns.

The first is a plain subclass with drawing, layers, or a few subviews managed in code. You drag several UIView objects into a storyboard and set each one to the same custom class.

The second is a XIB-backed view. In that setup, the custom class loads its internal content from a separate nib file. This is usually the better choice when the view has labels, images, stack views, and constraints that you want to design visually once and reuse many times.

A Minimal Custom UIView Subclass

Here is a simple reusable card view with inspectable properties:

swift
1import UIKit
2
3@IBDesignable
4final class CardView: UIView {
5    @IBInspectable var cornerRadius: CGFloat = 12 {
6        didSet { applyStyle() }
7    }
8
9    @IBInspectable var borderWidth: CGFloat = 1 {
10        didSet { applyStyle() }
11    }
12
13    @IBInspectable var borderColor: UIColor = .lightGray {
14        didSet { applyStyle() }
15    }
16
17    override init(frame: CGRect) {
18        super.init(frame: frame)
19        commonInit()
20    }
21
22    required init?(coder: NSCoder) {
23        super.init(coder: coder)
24        commonInit()
25    }
26
27    override func prepareForInterfaceBuilder() {
28        super.prepareForInterfaceBuilder()
29        applyStyle()
30    }
31
32    private func commonInit() {
33        backgroundColor = .white
34        applyStyle()
35    }
36
37    private func applyStyle() {
38        layer.cornerRadius = cornerRadius
39        layer.borderWidth = borderWidth
40        layer.borderColor = borderColor.cgColor
41        layer.masksToBounds = true
42    }
43}

To instantiate multiple copies in Interface Builder, drag several UIView objects into the storyboard, then set each one to class CardView in the Identity Inspector. Each instance can have different inspectable values.

When A Separate XIB Is Better

If the view has a more complex layout, place that layout in ProfileBadgeView.xib and load it from the class. This keeps the layout reusable and avoids duplicating subviews manually in every storyboard scene.

swift
1import UIKit
2
3final class ProfileBadgeView: UIView {
4    @IBOutlet private weak var nameLabel: 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        loadNib()
11    }
12
13    required init?(coder: NSCoder) {
14        super.init(coder: coder)
15        loadNib()
16    }
17
18    func configure(name: String, subtitle: String) {
19        nameLabel.text = name
20        subtitleLabel.text = subtitle
21    }
22
23    private func loadNib() {
24        Bundle.main.loadNibNamed("ProfileBadgeView", owner: self, options: nil)
25        contentView.frame = bounds
26        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
27        addSubview(contentView)
28    }
29}

In ProfileBadgeView.xib, set the File's Owner to ProfileBadgeView, connect contentView, nameLabel, and subtitleLabel, and design the internal layout there.

How To Instantiate Multiple Copies In IB

For storyboard use, add a plain UIView wherever you need the reusable component and set its custom class to ProfileBadgeView. Do that as many times as needed in the same scene or across scenes.

The important point is that Interface Builder does not create one singleton instance of your custom view class. Every UIView placeholder you add to the storyboard becomes a separate runtime instance. If five storyboard views are assigned to ProfileBadgeView, you will get five separate ProfileBadgeView objects.

If each instance needs unique data, expose properties or a configure method and set them from the owning view controller.

swift
1final class ViewController: UIViewController {
2    @IBOutlet private weak var badgeA: ProfileBadgeView!
3    @IBOutlet private weak var badgeB: ProfileBadgeView!
4
5    override func viewDidLoad() {
6        super.viewDidLoad()
7        badgeA.configure(name: "Alice", subtitle: "Admin")
8        badgeB.configure(name: "Bob", subtitle: "Reader")
9    }
10}

Design-Time Support In Interface Builder

@IBDesignable and @IBInspectable are useful, but keep expectations realistic. They help preview simple style changes, but more complex runtime-only logic may not render correctly inside Interface Builder. Use them for convenience, not as a hard requirement for correctness.

For XIB-backed views, design-time rendering can be finicky. The reusable architecture still works even if Interface Builder previews are imperfect.

Avoid Common Wiring Mistakes

Most failures come from incorrect nib wiring rather than from the subclass itself. The usual setup mistakes are:

  • forgetting to connect contentView
  • setting the XIB root view class incorrectly
  • setting the storyboard placeholder to UIView instead of the custom subclass
  • loading the nib with the wrong file name
  • adding constraints inside the XIB but not letting the loaded content fill the outer view bounds

When debugging, confirm that init(coder:) runs, the nib loads, and the outlet connections are non-null.

Common Pitfalls

  • Building a complex reusable view entirely in a storyboard scene and then copying it manually instead of extracting it into a subclass or XIB.
  • Assuming one custom class means one shared instance. Every storyboard placeholder becomes its own object.
  • Forgetting to call common initialization code from both initializers.
  • Not exposing a configuration API, which forces view controllers to reach into subviews directly.
  • Relying on Interface Builder preview behavior instead of testing the runtime view on device or simulator.

Summary

  • Subclass UIView and assign that class to multiple storyboard UIView instances.
  • Use a plain subclass for simple reusable styling.
  • Use a XIB-backed view for more complex reusable layouts.
  • Each Interface Builder placeholder becomes a separate runtime instance of the custom class.
  • Expose a small configuration API so each instance can be initialized with different data.

Course illustration
Course illustration

All Rights Reserved.