Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a generic UViewController initialiser

I'm trying to create a UIViewController extension that I can use to initialise new instances. For each view controller in my project I have a corresponding storyboard.

i.e.

EditSomethingViewController.swift
EditSomethingViewController.storyboard

This is what I have so far:

extension UIViewController {

    static func initalize() -> UIViewController? {
        let name = String(self)

        let storyboard = UIStoryboard(name: name, bundle: nil)

        return storyboard.instantiateInitialViewController()
    }

}

However this means that when I use it, I still have to cast the response.

i.e.

if let viewController = EditSomethingViewController.initalize() as? EditSomethingViewController {
     // do something with view controller here  
}

Is it possible to create the extension in such a way that means I don't have to cast the response?

p.s. Working on an old project written in Swift 2.3 so would appreciate answers that are supported.

like image 368
Ollie Avatar asked May 09 '17 15:05

Ollie


People also ask

How do you create a new ViewController in a storyboard?

To create a new view controller, select File->New->File and select a Cocoa Touch Class. Choose whether to create it with Swift or Objective-C and inherit from UIViewController . Don't create it with a xib (a separate Interface Builder file), as you will most likely add it to an existing storyboard.

How do I set the identifier for ViewController in storyboard?

Step 1: Set a Storyboard IDIn the Storyboard, select the view controller that you want to instantiate in code. Make sure the yellow circle is highlighted, and click on the Identity Inspector. Set the custom class as well as the field called "Storyboard ID". You can use the class name as the Storyboard ID.

How do I get ViewController from view?

If you need to find the view controller that is responsible for a particular view, the easiest thing to do is walk the responder chain. This chain is built into all iOS apps, and lets you walk from one view up to its parent view, its grandparent view, and so on, until it reaches a view controller.

What is a UIViewController?

The UIViewController class defines the shared behavior that's common to all view controllers. You rarely create instances of the UIViewController class directly. Instead, you subclass UIViewController and add the methods and properties needed to manage the view controller's view hierarchy.


2 Answers

I use this extension:

extension UIViewController
{
    class func instantiateFromStoryboard(_ name: String = "Main") -> Self
    {
        return instantiateFromStoryboardHelper(name)
    }

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

Usage:

let controller = MyViewController.instantiateFromStoryboard()
like image 169
ChikabuZ Avatar answered Sep 28 '22 06:09

ChikabuZ


I assume that you don't want to make every one of your VCs conform to a protocol manually. That would be too much work :)

I haven't tested this but this should work:

protocol Initializable {
    static func initalize() -> Self?
}

extension UIViewController: Initializable {
    static func initalize() -> Self? {
        let name = NSStringFromClass(self as! AnyClass)

        let storyboard = UIStoryboard(name: name, bundle: nil)

        return storyboard.getInitialVC(type: self)
    }
}

extension UIStoryboard {
    func getInitialVC<T: UIViewController>(type: T.Type) -> T? {
        return instantiateInitialViewController() as? T
    }
}
like image 41
Sweeper Avatar answered Sep 28 '22 08:09

Sweeper