iOS development tips: How to instantiate UIViewController from Storyboard

Sergy Polkovnikov
2 min readMar 20, 2023

--

In this article, I’d like to show how to instantiate a UIViewController from a Storyboard using a protocol-oriented approach.

Usually to create view controllers from UIStoryboard, we use the instantiateViewController(withIdentifier:) method of the UIStoryboard class to create an instance of the desired view controller. For example:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "MyViewController")

This approach works, but it can be tedious if you have a large number of view controllers in your project, and reusing the code across multiple view controllers can be challenging.

To address these issues, we can use a protocol-oriented approach to instantiate view controllers from a UIStoryboard.

To make it easier to explain, I created a small project (download) with three Storyboards.

They are called: Selection.storyboard, Dogs.storyboard, Cats.storyboard. In order to make everything work as it should, you need to fill in the Storyboard ID field with the name of the controller class. For example, as in the picture:

We’ll start by creating shortcuts that represent our Storyboards.

enum Storyboard: String {
case Selection
case Dogs
case Cats

var instance : UIStoryboard {
return UIStoryboard(name: self.rawValue, bundle: Bundle.main)
}
}

We then add a function that instantiates a UIViewController.

func viewController<T: UIViewController>() -> T {
let identifier = String(describing: T.self)
guard let viewController = self.instance.instantiateViewController(withIdentifier: identifier) as? T else {
fatalError("Failed to instantiate view controller with identifier \(identifier)")
}
return viewController
}

Next, we define a protocol that all of our view controllers will conform to:

protocol Storyboarded {
static func containingStoryboard() -> Storyboard
}

extension Storyboarded where Self: UIViewController {
static func instantiate() -> Self {
let controller: Self = containingStoryboard().viewController()
return controller
}
}

We then extend the DogsViewController class to conform to the Storyboarded protocol.

class DogsViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}

extension DogsViewController: Storyboarded{
static func containingStoryboard() -> Storyboard {
return .Dogs
}
}

Now, any view controller that conforms to the Storyboarded protocol can be instantiated from a UIStoryboard by calling its instantiate() method.

@IBAction func selectDog(_ sender: Any) {
self.navigationController?.pushViewController(DogsViewController.instantiate(), animated: true)
}

That’s it. Everything is ready.

By using a protocol-oriented approach, we’ve simplified the process of instantiating view controllers from a UIStoryboard and made it easy to reuse this code across multiple view controllers in our project.

Please let me know in comments if you are using this approach? Share your experience and suggestions.

Clap 👏 if this article helps you.

Download project repository

--

--

Sergy Polkovnikov
0 Followers

iOS & Android developer | Alphyn Apps tech lead | Started programming in 1998: C++, C#, MCSD certification, Swift (Objective C), Kotlin (Java) in background