How do I make a custom initializer for a UIViewController subclass in Swift?
class ViewController: UIViewController { var imageURL: NSURL? // this is a convenient way to create this view controller without a imageURL convenience init() { self.init(imageURL: nil) } init(imageURL: NSURL?) { self.imageURL = imageURL super.init(nibName: nil, bundle: nil) } // if this view controller is loaded from a storyboard, imageURL will be nil required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }}
For those who write UI in code
class Your_ViewController : UIViewController { let your_property : String init(your_property: String) { self.your_property = your_property super.init(nibName: nil, bundle: nil) } override func viewDidLoad() { super.viewDidLoad() } required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }}
This is very similar to the other answers, but with some explanation. The accepted answer is misleading because its property is optional and doesn't expose the fact that your init?(coder: NSCoder)
MUST initialize each and every property and the only solution to that is having a fatalError()
. Ultimately you could get away by making your properties optionals, but that doesn't truly answer the OP’s question.
// Think more of a OnlyNibOrProgrammatic_NOTStoryboardViewControllerclass ViewController: UIViewController { let name: String override func viewDidLoad() { super.viewDidLoad() } // I don't have a nib. It's all through my code. init(name: String) { self.name = name super.init(nibName: nil, bundle: nil) } // I have a nib. I'd like to use my nib and also initialze the `name` property init(name: String, nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle? ) { self.name = name super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } // when you do storyboard.instantiateViewController(withIdentifier: "ViewController") // The SYSTEM will never call this! // it wants to call the required initializer! init?(name: String, coder aDecoder: NSCoder) { self.name = "name" super.init(coder: aDecoder) } // when you do storyboard.instantiateViewController(withIdentifier: "ViewController") // The SYSTEM WILL call this! // because this is its required initializer! // but what are you going to do for your `name` property?! // are you just going to do `self.name = "default Name" just to make it compile?! // Since you can't do anything then it's just best to leave it as `fatalError()` required init?(coder aDecoder: NSCoder) { fatalError("I WILL NEVER instantiate through storyboard! It's impossible to initialize super.init?(coder aDecoder: NSCoder) with any other parameter") }}
You basically have to ABANDON loading it from storyboard. Why?
Because when you call a viewController storyboard.instantiateViewController(withIdentifier: "viewController")
then UIKit will do its thing and call
required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder)}
You can never redirect that call to another init method.
Docs on
instantiateViewController(withIdentifier:)
:Use this method to create a view controller object to present programmatically. Each time you call this method, it creates a new instance of the view controller using the
init(coder:)
method.
Yet for programmatically created viewController or nib created viewControllers you can redirect that call as shown above.