How to Hide Long UIViewController
Loading Syntax From the UIStoryboard
If you are using storyboards for building your screens, and want to instantiate UIViewController
from within your code, you have probably used syntax similar to this:
let userProfileViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "UserProfileViewController") as! UserProfileViewController
let alsoUserProfileViewController = userProfileViewController.storyboard?.instantiateViewController(withIdentifier: "UserProfileViewController") as! UserProfileViewController
let otherViewController: UserProfileViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "UserProfileViewController") as! UserProfileViewController
let longSyntaxViewController: UserProfileViewController = otherViewController.storyboard?.instantiateViewController(withIdentifier: "UserProfileViewController") as! UserProfileViewController
Let’s be honest - this is ugly. And long.
And unfortunately this is not atypical. Examples need to have a reference to a UIStoryboard
object, either by using a .storyboard
property of some other UIViewController
instance or by creating a new UIStoryboard
object. Add type casting to that, and you get one very long line of code.
As a rule of thumb, if a line of code is longer than 80 characters, then that is often a good sign that the code should be restructured or simplified.
Let’s try to do something about this. One approach we can take is to create a UIStoryboard
extension and move it into a separate file. You could name it UIStoryboard+Loader.swift
, for example.
import UIKit
fileprivate enum Storyboard : String {
case main = "Main"
// add enum case for each storyboard in your project
}
fileprivate extension UIStoryboard {
static func loadFromMain(_ identifier: String) -> UIViewController {
return load(from: .main, identifier: identifier)
}
// optionally add convenience methods for other storyboards here ...
// ... or use the main loading method directly when
// instantiating view controller from a specific storyboard
static func load(from storyboard: Storyboard, identifier: String) -> UIViewController {
let uiStoryboard = UIStoryboard(name: storyboard.rawValue, bundle: nil)
return uiStoryboard.instantiateViewController(withIdentifier: identifier)
}
}
// MARK: App View Controllers
extension UIStoryboard {
class func loadUserProfileViewController() -> UserProfileViewController {
return loadFromMain("UserProfileViewController") as! UserProfileViewController
// or a bit longer syntax if you did not add convenience method in the fileprivate extension
// return load(from: .main, identifier: "UserProfileViewController") as! UserProfileViewController
}
// add other app view controller load methods here ...
}
Now, UIStoryboard
loading and instantiation of UIViewController
instances can be shortened to this:
let userProfileViewController = UIStoryboard.loadUserProfileViewController()
Having your code organized like this, you can have a centralized place for managing your UIViewControllers
in your project, which enables you to deal with all view controller identifier Strings
and type casting in one place. Also, you don’t have to worry about how to get the UIStoryboard
object when instantiating a UIViewController
from your app code.
If your codebase is large and you have lots of storyboards in there, then a solution like this can help you better organize your code.