Goal: I'm trying to restore state on a tab controller-based app (with navigation controllers on each tab).
Problem: On relaunch, the selected tab seems to be restored as expected, but the navigation hierarchy inside said tab is not.
Development:
- I first started with the project template "Tab based app".
- Next, I added restoration IDs to both child view controllers and the tab bar controller.
- In the app delegate, I implemented
application(_:shouldSaveApplicationState:)
andapplication(_:shouldRestoreApplicationState:)
.
I run then app, switch to the second (right) tab, hit home, terminate. o relaunch, the right tab is displayed (as expected). So far so good.
- Next, I go to the storyboard and embed both child view controllers in respective navigation controllers, and assign restoration IDs to those too.
I run the app, and restoration still works. Still good.
Next, I add a "detail" view controller; its class is a custom subclass of
UIViewController
to the storyboard, with properties to configure the contents of a debug label and its view's background color.I placed a "Show Detail..." button on each of the tabs' top view controllers, and create a segue from each into the (shared) detail view controller. So now my storyboard looks like a hexagon (also, both segues have identifiers set in Interface Builder). So, both left and right top view controllers share the same type of "detail" view controller. On show, it is configured so as to distinguish from where it has been pushed (see next point).
On each of the top view controllers'
prepareForSegue(_:sender:)
method, I configure the pushed detail view controller differently: Different text and background color ("left" and blue, and "right" and red, respectively).I added code to the detail view controller to save and restore the state of the text and background color properties:
encodeRestorableStateWithCoder(_:)
anddecodeRestorableStateWithCoder(_:)
. Also, I implementedviewDidLoad()
so as to reflect those properties' values in the view. Whenever it is instantiated and pushed into the navigation through a segue, the properties are first set and then used to configre the view inviewDidLoad()
. Whenever it is instantiated during restoration, the properties are set indecodeRestorableStateWithCoder(_:)
and similarly used inviewDidLoad()
.
...but when I run this code, the last selected tab is restored but only up to the top view controller -left or right-, not the detail. Interestingly, the background color last set to the detail view controller flashes for an instant.
I placed break points in encodeRestorableStateWithCoder(_:)
and decodeRestorableStateWithCoder(_:)
, but only the first of them is executed (encode).
- Wondering what might be missing, I went ahead and implemented the app delegate's
application(_:viewControllerWithRestorationIdentifierPath:coder:)
(returning always nil, but logging the path components passed).
The documentation is not very clear on whether this method is needed or not, and in any case all view controllers except the detail seem to be restored perfectly even without it. I added code to instantiate each view controller based on the last path component (i.e., that controller's restoration ID) and returning it.
Now, the decodeRestorableStateWithCoder(_:)
is called, but the navigation still goes back to the tab's top view controller after a split second.
So, what is going on? What am I missing to implement State Preservation and Restoration in a Tab Bar + Navigation Controller app?