I realize that this might be difficult to achieve, but I would like to be able to initialize ViewControllers
from storyboard
using init(coder: NSCoder)
function directly. I mean not using storyboard.instantiateViewController(identifier: coder: )
– I know I could use this, but this is what I would like to skip. Instead I would prefer to have a init in ViewController
like this:
init(viewModel: ViewModel)
and use this init to initialize this ViewController
from the storyboard
. Inside this init I imagine having some mechanism that would open my storyboard
, and extracted it’s coder somehow, so that I could write:
static let storyboard = UIStoryboard(named: "Game")
private let viewModel: ViewModel
init(viewModel: ViewModel) {
self.viewModel = viewModel
let identifier = String(describing: Self.self)
let coder: NSCoder = Self.storyboard.somehowGetTheCoderForViewController(withId: identifier)
super.init(coder: coder)
}
Problem is how to read storyboard in such a way that I was able to get the coder of particular ViewController from it.
Again – I know this can be solved by using something like this
storyboard.instantiateViewController(identifier: String(describing: Self.self)) { coder in
Self.init(coder: coder, viewModel: viewModel)
}
But Im looking for a way to not use instantiateViewController
, and just be able to get the coder
, so that later I could just initiate
VC like this:
let viewController = ViewContorller(viewModel: viewModel)
So the question is how to unpack storyboard
, and retrieve coder
object for some ViewController
.
2
Answers
You are not supposed to do this.
As the documentation of
init(nibName:bundle:)
says:When initialising a VC using an initialiser, that initialiser is what you should use, not
init(coder:)
. If you use storyboards, then you should useinstantiateViewController
, or use segues to get new VCs.So to achieve this syntax:
You can put your VCs in xib files, and do:
If you must use storyboards, then you can’t use an initialiser syntax for initialising VCs. You can instead make a factory method, such as:
And implement it using
UIStoryboard.instantiateViewController
.This is why the initializer
instantiateViewController(identifier:creator:)
exists.https://developer.apple.com/documentation/uikit/uistoryboard/3213989-instantiateviewcontroller
You receive the
coder
and use it to call a custom initializer that itself calls thecoder
initializer but also does other custom initialization.To illustrate, suppose we have a ViewController class with a
message
String property to be presented to the user in a UILabel when the view appears. So we’ve given ViewController aninit(coder:message:)
initializer:Left to its own devices, however, the runtime will never call our
init(coder:message:)
initializer; it knows nothing of it! The only way the runtime knows to instantiate a view controller from a storyboard is by callinginit(coder:)
. But we can callinit(coder:message:)
when we instantiate the view controller from the storyboard.Suppose this is the storyboard’s initial view controller, and we’re calling it in the scene delegate at launch time:
We call
instantiateViewController(identifier:creator:)
and thecreator:
function callsinit(coder:message:)
— which, in turn, callsinit(coder:)
. Thus our use of thecreator:
function is legal, and the view appears correctly.