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.
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()
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
}
}
You can change the return type to be Self
which will match the type you are calling the method on.
This is a method I've used to do this. It will need to be put into a protocol extension instead.
static func loadFromStoryboard() -> Self? {
let storyboard = UIStoryboard(name: NSStringFromClass(self),
bundle: Bundle(for: self))
return storyboard.instantiateInitialViewController() as? Self
}
来源:https://stackoverflow.com/questions/43874430/creating-a-generic-uviewcontroller-initialiser