0

The Goal

I want to call the instantiateViewControllerWithIdentifier method on a Storyboard to get a view controller. But I want to do it with generics for code reuse and simplicity.

The Non-Compiling Code

let viewController = StoryboardHelper.viewControllerFromStoryboard<ChooseProviderViewController>()

class func viewControllerFromStoryboard<T>() -> T {
        let storyboard = mainStoryboard()
        let viewController = storyboard.instantiateViewControllerWithIdentifier(resolveViewController(T)) as T

        return viewController
    }

private class func resolveViewController<T>() -> String {
        if T is ChooseProviderViewController {
            return chooseProviderViewControllerIdentifier;
        }

        return ""
    }

Now, the above code is what I have at the moment, and how I would like the API to be. It would be nice to say "StoryboardHelper, here is the type of the view controller I want, go get the view controller instance for me".

So, in the end, I would like some way to do this:

let instanceOfXViewController = StoryboardHelper.viewControllerFromStoryboard<XViewController>()

let instanceOfYViewController = StoryboardHelper.viewControllerFromStoryboard<YViewController>()
Cloud9999Strife
  • 3,102
  • 3
  • 30
  • 43
  • Your approach isn't foolproof: ViewControllerClass != StoryboardIdentifier. How will you differentiate if there are multiple scenes using the same view controller class, but different storyboard identifiers? – Stuart Jan 31 '15 at 14:08
  • That's the purpose of the resolveViewController method it returns the correct storyboard identifiers. The identifiers will be hard-coded but I'm ok with that for now. – Cloud9999Strife Jan 31 '15 at 14:25
  • I posted an answer before, somewhat related to what you want. http://stackoverflow.com/a/26114926/2681195 – findall Feb 01 '15 at 14:51

1 Answers1

1

I have a answer for you but it will only work with Swift 1.2 (+), in 1.1 it will return a intance of the wrong (super) type. I changed it to a more general situation/naming but it is effectly the same problem. First since you only want to manage UIViewControllers you should restrict T. Like <T:UIViewController> . Secondly you should/can pass the Type as an argument and create an instance of it.

import Foundation

class Helper {
    class func instanceFromT<T:R>(T.Type) -> T {
        return T.self()
    }
}

class R {
    required init () {

    }
    func me() -> String {
        return "me is R"
    }
}

class B : R {
    override func me() -> String {
        return "me is B"
    }
}

class A : R {
    override func me() -> String {
        return "me is A"
    }
}

let my = Helper.instanceFromT(A.self)

println(my.me()) // "me is A"
Alex
  • 541
  • 5
  • 19