Recently, I have been trying to use storyboards as… storyboards — a place where one can see an overview of the app at a glance.

The main drawback is that for instantiation you need a storyboard & controller id + cast. And of course — you can not have custom init methods for dependency injection.

To simplify this, you can use a generic extension on UIViewController that uses type inference to determine the appropriate StoryboardId:

extension UIViewController { class func instantiateFromStoryboard<T: UIViewController>(_ storyboardName: String) -> T { let storyboard = UIStoryboard(name: storyboardName, bundle: nil) let controller = storyboard.instantiateViewController(withIdentifier: String(describing: self)) as! T return controller } }

The only requirement is that you set the Storyboard ID for each scene in your storyboard to the class name of the View Controller. If you do not do that, you will get runtime errors.

You can then instantiate your view controller as

let homeVC: HomeViewController = UIViewController.instantiateFromStoryboard("Main")

I break down my storyboards into functional parts and so I can instantiate a view controller from any storyboard. To simplify instantiation and to introduce a bit of type safety into the stringly typing of the storyboards, you can define a protocol per Storyboard:

extension MainStoryboard where Self: UIViewController {

static func instantiate() -> Self {

return instantiateFromStoryboard("Main")

}

}

Then you conform the controllers for each storyboard to the relevant protocol:

class HomeViewController: UIViewController, MainStoryboard {

...

}

The beauty of this is that you no longer have to specify the type of the variable:

let homeVC = HomeViewController.instantiate()

homeVC is now of type HomeViewController.

It is important to note that this approach will not work with Segues.