I'm trying to implement state restoration in an app that uses iOS 6+ and storyboards, but I am having problems finding a way to prevent duplicate calls to heavy methods.
If I simply start the app, then I need to setup the UI in viewDidLoad
:
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
}
This works fine in a normal, non-state-restoration world. Now I've added state restoration and after restoring some properties I need to update the UI with those properties:
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
[super decodeRestorableStateWithCoder:coder];
// restore properties and stuff
// [...]
[self setupUI];
}
So what happens now is that first the setupUI
method is called from viewDidLoad
, and then again from decodeRestorableStateWithCoder:
. I don't see a method that I can override that's always called last.
This is the normal order of method calls:
When using state restoration, this is called:
I can't place the call to setupUI
in viewWillAppear
because then it would also be executed every time you native back to a view.
It would be much handier if decodeRestorableStateWithCoder
was called BEFORE viewDidLoad
because then you could use restored properties. Sadly that not the case, so... how can I prevent doing the work in viewDidLoad
when I know that I need to do it all over again in decodeRestorableStateWithCoder
right after?
State restoration is an often-overlooked feature in iOS that lets a user return to their app in the exact state in which they left it – regardless of what's happened behind the scenes. At some point, the operating system may need to remove your app from memory; this could significantly interrupt your user's workflow.
The UIViewController class defines the shared behavior that's common to all view controllers. You rarely create instances of the UIViewController class directly. Instead, you subclass UIViewController and add the methods and properties needed to manage the view controller's view hierarchy.
A view controller manages a single root view, which may itself contain any number of subviews. User interactions with that view hierarchy are handled by your view controller, which coordinates with other objects of your app as needed. Every app has at least one view controller whose content fills the main window.
If you're doing state restoration programatically (i.e. not using storyboards), you can use + viewControllerWithRestorationIdentifierPath:coder:
, init the view controller there and use whatever you need from the coder to do your pre-viewDidLoad initialization.
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder
{
if ([[identifierComponents lastObject] isEqualToString:kViewControllerRestorationIdentifier]) {
if ([coder containsValueForKey:kIDToRestore]) {
// Can only restore if we have an ID, otherwise return nil.
int savedId = [coder decodeIntegerForKey:kIDToRestore];
ViewController *vc = [[ViewController alloc] init];
[vc setThingId:savedId];
return vc;
}
}
return nil;
}
I've found that trying to implement state restoration has shown up bad programming practices in my code, like packing too much into viewDidLoad
. So while this works (if you're not using storyboards), the other option is to refactor how you're setting up your view controllers. Instead of using a flag, move code pieces to their own methods and call those methods from both places.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With