State Preservation & Restoration
One of the new features in iOS 6 that hasn’t exactly been shouted out from the rooftops is state preservation, probably because on paper it’s far from exciting. However, having implemented it into an app I’ve realised there are some great benefits - not least of which is making your users happier.
What it does
State preservation is designed to solve the problem of app termination. The majority of iOS users don’t know the difference between application backgrounding and application termination. Anecdotally, many people who test the apps I work on are unaware that removing apps from the ‘recent apps’ list terminates them completely.

This can result in quite a confusing and frustrating experience: sometimes coming into an app will take you back to where you were last, and at others you’ll be back to square one. Some developers had attempted to solve this by keeping track of the current app state and attempting to restore it upon relaunch. Inevitably this led to a number of different approaches, some good and some bad.
The good news is that iOS 6 now offers state preservation out of the box, and enabling it is a simple two step process:
How to enable it
Step 1: Label your Controllers
To keep track of a user’s journey through an app you need to provide restoration identifiers for your view controllers. You can identify as many or as few controllers as you wish, but only controllers with restoration identifiers present will automatically instantiated and navigated to by iOS upon launch.
If you’re working with XIBs you can add identifiers within Interface Builder - and with Storyboards it’s even easier (since Storyboards already track a user’s progress through an app). In code you can simply set the restorationIdentifier property.
Step 2: Opt In to Restoration and Preservation
Currently, state preservation is ‘opt in’. To opt in you need to implement three methods in your application delegate, described below:
- (BOOL)application:shouldRestoreApplicationState:
Sometimes you might not want iOS to automatically restore the user’s state: perhaps your app has had a major UI update, and the area of the app your user was last in no longer exists. You should return YES to enable restoration.
- (BOOL)application:shouldSaveApplicationState:
As above, except this method is called when you application is terminated. Again, return YES to allow iOS to save the most recent state information.
- (BOOL)application:willFinishLaunchingWithOptions:
To support state restoration a new launching method has been introduced that complements the more traditional didFinishLaunching. willFinish is called before the state is restored, and didFinish is called afterwards. You’ll probably therefore want to split your launching code across these two methods: code that is required for your app to run should go in willFinish. Final completion code should go in didFinishLaunching. What counts as ‘final completion code’? Things like checking whether a user is logged in, where you might want to display a modal login page rather than your app itself, for example.
Backwards Compatibility
If you’d like to support iOS 4 and 5 users (where state preservation is not supported) you’ll need to watch out for a few things. Firstly, be sure to test that restoration identifiers are supported using respondsToSelector (if you’re using IB you can skip this step):
if ([self respondsToSelector:@selector(restorationIdentifier)]) {
self.restorationIdentifier = @"Home Controller";
}
However, a more serious issue is how to deal with the new willFinishLaunchingWithOptions method, which is only available on iOS 6, into which you’ve moved most of your launching logic. You could put your launch code into both willFinish and didFinishLaunching and conditionally test the current version of iOS, but this is unnecessary duplication.
Instead, you can use this great little trick which Apple recommend in their WWDC videos:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self commonLaunchInitialization:launchOptions];
// Code that must execute in didFinishLaunching whether state restoration is enabled or not
return YES;
}
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self commonLaunchInitialization:launchOptions];
return YES;
}
- (void)commonLaunchInitialization:(NSDictionary *)launchOptions {
static dispatch_once_t pred;
dispatch_once(&pred, ^{
// Your launch code here
});
If you are not familiar with Grand Central Dispatch you’re probably wondering what this code does. The dispatch_once GCD call is a clever method that is typically used when doing singleton work: it will execute it’s code block once only, and no nothing for any subsequent calls. This allows us to guarantee our launch logic will only be executed once, even though we’re calling commonLaunchInitialization in both didLaunch and willLaunch.
A Note on Testing
For reasons that will become quickly apparent, there are a few ‘gotchas’ involved with testing state restoration. Confusingly, terminating an app from the app switching pane disables restoration. Why? To prevent a mis-behaving or broken app from keeping a user stuck inside a loop. Perhaps the app has some terrible networking code that keeps the user locked inside a loading screen - resuming to that state would not be beneficial. Similarly, as you might expect state will not be resumed if your app didn’t terminate cleanly (i.e, it crashed).
So how do you test app switching? Well, when attached to the debugger you will want to exit to the home screen (by pressing the home button) and then terminate the app from Xcode (by hitting the ‘Stop’ button).