Awesome Swift extensions for UIViewController and UITableViewCell instantiation

Instantiating view controllers from storyboards is pretty annoying because it relies on a string being passed through correctly. Most people simply use the class name as the storyboard ID for their UIViewControllers:

MyViewController Storyboard setup

and then instantiate them in code like this:

let storyboard = UIStoryboard(name:"Main", bundle:nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MyViewController") as? MyViewController

I find it super ugly to have the name of the UIViewController duplicated as a string in my code, so I wrote up a storyboard extension that will do the work for me:

extension UIStoryboard {
    func instantiateViewController<T:UIViewController>(type: T.Type) -> T? {
        var fullName: String = NSStringFromClass(T.self)
        if let range = fullName.rangeOfString(".", options: .BackwardsSearch) {
            fullName = fullName.substringFromIndex(range.endIndex)
        }
        return self.instantiateViewControllerWithIdentifier(fullName) as? T
    }
}

The code is pretty simple; it pulls out the name of the class and instantiates with the name as a string. It's a testament to Swift's awesome generics that I can even write this kind of function.

Now I can just write this:

let storyboard = UIStoryboard(name:"Main", bundle:nil)
let vc = storyboard.instantiateViewController(MyViewController)
// vc is now an object of type MyViewController?

It doesn't look like much, but you should notice that now I'm not passing the name of the UIViewController as a string, I'm passing the actual type of the view controller instead 😎.

It's worth noting this isn't a perfect solution - I still use the class name of the ViewController as a string underneath, which means I still have to manually update the Storyboard ID of the UIViewController in the UIStoryboard. But, this has saved me loads of time and effort and I thought it would be worth sharing.

This technique works just as well with UITableViewCells:

extension UITableView {
    func dequeueReusableCell<T:UITableViewCell>(type: T.Type) -> T? {
        var fullName: String = NSStringFromClass(T.self)
        if let range = fullName.rangeOfString(".", options: .BackwardsSearch) {
            fullName = fullName.substringFromIndex(range.endIndex)
        }
        return self.dequeueReusableCellWithIdentifier(fullName) as? T
    }

    func dequeueReusableCell<T:UITableViewCell>(type: T.Type, forIndexPath indexPath:NSIndexPath) -> T? {
        var fullName: String = NSStringFromClass(T.self)
        if let range = fullName.rangeOfString(".", options: .BackwardsSearch) {
            fullName = fullName.substringFromIndex(range.endIndex)
        }
        return self.dequeueReusableCellWithIdentifier(fullName, forIndexPath:indexPath) as? T
    }
}

so I can now write more elegant code like this:

let cell = tableView.dequeueReusableCell(DocumentCell.self, forIndexPath:indexPath)!

(I'm not sure why I have to add the .self part if there's a second argument - if you do, let me know in the comments below 👍)

Pretty cool eh?

Oh, yes!

As usual, feel free to get in touch below 👊


© Krishan Patel 2015.