Fix NavigationViewController crash in storyboard.#2974
Conversation
| required public init(for route: Route, routeIndex: Int, routeOptions: RouteOptions, navigationOptions: NavigationOptions? = nil) { | ||
| super.init(nibName: nil, bundle: nil) | ||
|
|
||
| initialize(for: route, routeIndex: routeIndex, routeOptions: routeOptions, navigationOptions: navigationOptions) |
There was a problem hiding this comment.
I expected the fix to be in required public init?(coder aDecoder: NSCoder), does it work without this change?
There was a problem hiding this comment.
It'll not be possible to provide needed information in required public init?(coder aDecoder: NSCoder). E.g. route object should already be available before calling that initializer, which doesn't seem to be possible. Seems that the only way is to initialize all needed objects afterwards and only after that present NavigationViewController.
There was a problem hiding this comment.
Example in this guide shows how new usage can look like.
There was a problem hiding this comment.
I see your point now, the problem is that if a user forgets to call initialize method the app will crash. 😿
But I guess it's the best we can do, hope this problem will be noticeable during the development process.
There was a problem hiding this comment.
E.g.
routeobject should already be available before calling that initializer, which doesn't seem to be possible.
The separate initialize method is really unfortunate. Its name points to a larger problem: most of the stuff that has been happening in the initializer only needs to take place by the time the view controller is presented, right? Ideally we’d move it all into viewDidLoad(). As it is, developers using NavigationViewController programmatically have to be careful about prematurely initializing the object. Developers don’t expect initializing a view controller or view to have side effects. I guess the tradeoff is that delaying these steps until viewDidLoad() would force us to think about situations where navigationService etc. are nil, so we’d have to revisit a bunch of implicitly unwrapped optionals.
I guess I’m OK with this approach as a stopgap fix, but in that case we should think about a broader lifecycle cleanup as tail work, with an eye towards deprecating the new initialize method.
There was a problem hiding this comment.
I agree that additional initializer is not an optimal solution. I've changed implementation to use optional parameters for route, routeOptions routeIndex etc. User will be able to change it before NavigationViewController presentation. Example can be found here.
There was a problem hiding this comment.
The changelog should mention that developers can once again segue to Navigation.storyboard or add NavigationViewController to a storyboard, and that prepare(for:sender:) needs to call NavigationViewController.initialize(for:routeIndex:routeOptions:navigationOptions:).
| required public init(for route: Route, routeIndex: Int, routeOptions: RouteOptions, navigationOptions: NavigationOptions? = nil) { | ||
| super.init(nibName: nil, bundle: nil) | ||
|
|
||
| initialize(for: route, routeIndex: routeIndex, routeOptions: routeOptions, navigationOptions: navigationOptions) |
There was a problem hiding this comment.
E.g.
routeobject should already be available before calling that initializer, which doesn't seem to be possible.
The separate initialize method is really unfortunate. Its name points to a larger problem: most of the stuff that has been happening in the initializer only needs to take place by the time the view controller is presented, right? Ideally we’d move it all into viewDidLoad(). As it is, developers using NavigationViewController programmatically have to be careful about prematurely initializing the object. Developers don’t expect initializing a view controller or view to have side effects. I guess the tradeoff is that delaying these steps until viewDidLoad() would force us to think about situations where navigationService etc. are nil, so we’d have to revisit a bunch of implicitly unwrapped optionals.
I guess I’m OK with this approach as a stopgap fix, but in that case we should think about a broader lifecycle cleanup as tail work, with an eye towards deprecating the new initialize method.
|
|
||
| /** | ||
| Initializes a navigation view controller that presents the user interface for following a predefined route based on the given options. | ||
| Initializes a `NavigationViewController` that presents the user interface for following a predefined route based on the given options. |
There was a problem hiding this comment.
By the way, it’s OK to refer to the thing the class represents rather than the symbol. There’s no ambiguity because the developer would read this documentation comment in the context of the NavigationViewController class reference already.
6c9a4cf to
426df36
Compare
f21efec to
83a5ca8
Compare
83a5ca8 to
5311bab
Compare
Description
Fixes #2973.
Implementation
Since it's not possible to call other initializers in
NavigationViewController.init(coder:)new publicNavigationViewController.initialize(for:routeIndex:routeOptions:navigationOptions:)method was introduced. It's meant to be called right afterNavigationViewControllerinstantiation in storyboard. I've also brought backNavigationViewControllertoNavigation.storyboardto give the ability to create it using this guide.