State Restoration Tutorial: Getting Started
In this state restoration tutorial, learn how to use Apple’s State Restoration APIs to enhance a user’s experience of your app. By Luke Parham.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
State Restoration Tutorial: Getting Started
15 mins
The UIStateRestoring Protocol
When it comes to implementing state restoration, UIKit does a lot for you, but your app is responsible for a few things on its own:
- Telling UIKit it wants to participate in state restoration, which you did in your app delegate.
- Telling UIKit which view controllers and views should be preserved and restored. You took care of this by assigning restoration identifiers to your view controllers.
- Encoding and decoding any relevant data necessary to reconstruct the view controller to its previous state. You haven’t done this yet, but that’s where the
UIStateRestoring
protocol comes in.
Every view controller with a restoration identifier will receive a call to encodeRestorableStateWithCoder(_:)
of the UIStateRestoring
protocol when the app is saved. Additionally, the view controller will receive a call to decodeRestorableStateWithCoder(_:)
when the app is restored.
To complete the restoration flow, you need to add logic to encode and decode your view controllers. While this part of the process is probably the most time-consuming, the concepts are relatively straightforward. You’d usually write an extension to add conformance to a protocol, but UIKit automatically registers view controllers to conform to UIStateRestoring
— you merely need to override the appropriate methods.
Open PetDetailsViewController.swift and add the following code to the end of the class:
override func encodeRestorableStateWithCoder(coder: NSCoder) {
//1
if let petId = petId {
coder.encodeInteger(petId, forKey: "petId")
}
//2
super.encodeRestorableStateWithCoder(coder)
}
Here’s what’s going on in the code above:
- If an ID exists for your current cat, save it using the provided encoder so you can retrieve it later.
- Make sure to call
super
so the rest of the inherited state restoration functionality will happen as expected.
With these few changes, your app now saves the current cat’s information. Note that you didn’t actually save the cat model object, but rather the ID you can use later to get the cat object. You use this same concept when saving your selected cats in MatchedPetsCollectionViewController
.
Apple is quite clear that state restoration is only for archiving information needed to create view hierarchies and return the app to its original state. It’s tempting to use the provided coders to save and restore simple model data whenever the app goes into the background, but iOS discards all archived data any time state restoration fails or the user kills the app. Since your user won’t be terribly happy to start back at square one each time they restart the app, it’s best to follow Apple’s advice and only save state restoration using this tactic.
Now that you’ve implemented encoding in PetDetailsViewController.swift, you can add the corresponding decoding method below:
override func decodeRestorableStateWithCoder(coder: NSCoder) {
petId = coder.decodeIntegerForKey("petId")
super.decodeRestorableStateWithCoder(coder)
}
Here you decode the ID and set it back to the view controller’s petId
property.
The UIStateRestoring
protocol provides applicationFinishedRestoringState()
for additional configuration steps once you’ve decoded your view controller’s objects.
Add the following code to PetDetailsViewController.swift:
override func applicationFinishedRestoringState() {
guard let petId = petId else { return }
currentPet = MatchedPetsManager.sharedManager.petForId(petId)
}
This sets up the current pet based on the decoded pet ID and completes the restoration of the view controller. You could, of course, do this in decodeRestorableStateWithCoder(_:)
, but it’s best to keep the logic separate since it can get unwieldy when it’s all bundled together.
Build and run your app; navigate to a pet’s detail view and trigger the save sequence by backgrounding the app then killing it via Xcode. Re-launch the app and verify that your same furry friend appears as expected:
You’ve learned how to restore view controllers created via storyboards. But what about view controllers that you create in code? To restore storyboard-created views at run-time, all UIKit has to do is find them in the main storyboard. Fortunately, it’s almost as easy to restore code-based view controllers.
Restoring Code-based View Controllers
The view controller PetEditViewController
is created entirely from code; it’s used to edit a cat’s name and age. You’ll use this to learn how to restore code-created controllers.
Build and run your app; navigate to a cat’s detail view then click Edit. Modify the cat’s name but don’t save your change, like so:
Now background the app and kill it via Xcode to trigger the save sequence. Re-launch the app, and iOS will return you to the pet detail view instead of the edit view:
Just as you did for the view controllers built in Interface Builder, you’ll need to provide a restoration ID for the view controller and add the encode and decode UIStateRestoring
protocol methods to properly restore the state.
Take a look at PetEditViewController.swift; you’ll notice the encode and decode methods already exist. The logic is similar to the encode and decode methods you implemented in the last section, but with a few extra properties.
It’s a straightforward process to assign the restoration identifier manually. Add the following to viewDidLoad()
right after the call to super
:
restorationIdentifier = "PetEditViewController"
This assigns a unique ID to the restorationIdentifier
view controller property.
During the state restoration process, UIKit needs to know where to get the view controller reference. Add the following code just below the point where you assign restorationIdentifier
:
restorationClass = PetEditViewController.self
This sets up PetEditViewController
as the restoration class responsible for instantiating the view controller. Restoration classes must adopt the UIViewControllerRestoration
protocol and implement the required restoration method. To that end, add the following extension to the end of PetEditViewController.swift:
extension PetEditViewController: UIViewControllerRestoration {
static func viewControllerWithRestorationIdentifierPath(identifierComponents: [AnyObject],
coder: NSCoder) -> UIViewController? {
let vc = PetEditViewController()
return vc
}
}
This implements the required UIViewControllerRestoration
protocol method to return an instance of the class. Now that UIKit has a copy of the object it’s looking for, iOS can call the encode and decode methods and restore the state.
Build and run your app; navigate to a cat’s edit view. Change the cat’s name as you did before, but don’t save your change, then background the app and kill it via Xcode. Re-launch your app and verify all the work you did to come up with a great unique name for your furry friend was not all in vain!