An Overview of iOS 7 Application State Preservation and Restoration

From Techotopia
Revision as of 19:55, 27 October 2016 by Neil (Talk | contribs) (Text replacement - "<table border="0" cellspacing="0">" to "<table border="0" cellspacing="0" width="100%">")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
PreviousTable of ContentsNext
Scheduling iOS 7 Local NotificationsAn iOS 7 State Preservation and Restoration Tutorial


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


Application state preservation and restoration is all about presenting the user with application continuity in terms of appearance and behavior. This is, in part, already provided through support for applications to run in the background. Users have come to expect to be able to switch from one app to another and, on returning to the original app, to find it in the exact state it was in before the switch took place. Unless the application developer took specific steps to save and restore state, however, this continuity did not extend between sessions that involve the application stopping and restarting (usually as a result of the operating system killing a background application to free resources). For most applications available today, such a scenario results in the application starting at the home screen with no consideration being given to the previous state of the application.

Apple feels strongly that the continuity of a user’s interaction with an application should extend between the application stopping and restarting. In recognition of this fact, iOS 6 introduced a set of new features to the UIKit framework intended to make it easier for developers to save and restore application state.

The topic of this chapter is to introduce the concepts of application state preservation and restoration in iOS 7 and outline the steps that are involved in implementing this behavior.


Contents


The Preservation and Restoration Process

The UIKit preservation and restoration system provides a mechanism by which an application is able to save and restore the state of specific view controllers and views between different application invocations. UIKit achieves this by defining a flexible structure to which the application must conform in terms of providing information on what is to be saved, and implementing methods that are called by UIKit at certain points during the preservation and restoration process.

During the application design process, the developer must decide which view controllers and views that comprise the application need to have state preserved to ensure continuity for the user. Each item for which state is to be saved must then be assigned a restoration identifier. Those views and view controllers without a restoration ID will not, by default, be included in the saved state. It should also be noted that if a view controller does not have a restoration ID, none of the controller’s child views or view controllers will be saved, irrespective of whether or not those sub-views have a restoration ID.

Each time a running application is placed into the background, UIKit will ask the application whether or not it requires state preservation. In the event that the application requires the state to be saved, UIKit will traverse the view controller hierarchy of the application and save the state of each object that has a restoration ID. As it does this, it will call a method on each eligible object in order to provide that object with an opportunity to encode and return additional data to be included in the saved state. Once the state information has been gathered, it is saved to a file on the local file system of the device.

When the application is next launched (as opposed to being brought out of the background and into the foreground) UIKit will look for a saved state file for the application. In the event that it finds one, it will ask the application if state restoration is required. If the application responds affirmatively, UIKit will use the saved state to guide the application through the process of re-creating the views and view controllers to the previous state. As will be seen later in this chapter, the exact sequence of events for this restoration will depend on the nature of the application, but essentially involves UIKit making calls to specific methods (primarily on the application delegate) asking for the objects to be recreated. Once the view controller and view objects have been recreated, UIKit calls methods on those objects passing through any additional data that was saved during the preservation process.

Opting In to Preservation and Restoration

By default, UIKit does not attempt to save and restore the state of an application. An application must, instead, “opt-in”. This is achieved by implementing methods in the application delegate which return a boolean value to indicate whether or not preservation and restoration are required. The following methods, for example, indicate to UIKit that both state restoration and preservation are required:

-(BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
        return YES;
}

-(BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
        return YES;
}

Assigning Restoration Identifiers

When UIKit walks the view controller hierarchy of an application to preserve state, only those objects with a restoration ID will be saved.

Restoration IDs can be assigned to objects either in code or from within Interface Builder. The restoration ID can be any valid string and may be assigned in code via the restorationID property of the UIView and UIViewController classes. For example:

myViewController.restorationIdentifier = @”myFirstView”;

When using Interface Builder, the restoration ID may be assigned by selecting the object and entering the ID into the Restoration ID field located in the Identity section of the Identity Inspector as illustrated in Figure 64-1.

In the case of storyboards, the restoration ID can be set to use the storyboard ID if one has already been assigned.


Configuring a restoration ID in Xcode 5 for an iOS 7 app

Figure 64-1


When assigning restoration IDs in Interface Builder, it is important to distinguish between views and view controllers. Clicking on the white background of a view in a storyboard, for example, will select the UIView object, not the view controller. Clicking on the status bar containing the battery life indicator will, on the other hand, select the view controller. As a general rule, wherever possible, state preservation should be implemented by saving and restoring the state of the view controller which, in turn, will be responsible for restoring the state of any child view objects. Directly saving and restoring the state of individual view objects in a user interface layout should only be performed when preservation requirements cannot be met using the view controller state.

Default Preservation Features of UIKit

Once state preservation has been enabled and restoration identifiers assigned appropriately, it is worth being aware that UIKit will preserve certain state information by default and without the need to write any additional code. By default, the following state information is saved and restored automatically for view controllers:

  • Currently presented view controller
  • Currently selected tab
  • State of navigation stacks

In the case of views, the following is preserved by default:

  • Current scroll position
  • Currently selected cell in a table view
  • Current state of an image view (zoom, pan, etc)
  • Web history (including scroll position and zoom level)

Additional state preservation will, as will be outlined in the remainder of this chapter, require some coding.

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

Saving and Restoring Additional State Information

So far we have ascertained that UIKit will store information about which view controllers and views are to be saved based on whether or not those objects have a restoration ID. In many cases, each object will have additional information that it needs to save in order to restore the application exactly as the user left it. This might, for example, relate to a specific item the user has selected, or some text that has been entered into a Text View but not yet been committed to the application’s data model. Fortunately, UIKit has a way to handle this.

Once UIKit discovers, for example, that the state of a specific view controller is to be saved, it will check to see if a method named encodeRestorableStateWithCoder has been implemented in that object’s class. If the method has been implemented, UIKit will call that method, passing through a reference to an NSCoder object. It is then the responsibility of that method to store any additional state data that needs to be preserved into that NSCoder object before returning. UIKit will then save that NSCoder object along with the rest of the application’s state.

When UIKit restores the view controller object on a subsequent launch of the application, it will call the decodeRestorableStateWithCoder method of that object, passing through the NSCoder object containing the previously stored state data. The method is then responsible for decoding the object and using the data contained therein to restore the view to the previous state. The following code listing shows an example implementation of these two methods for a view controller class intended to save any text that has been entered by the user but not yet saved to the applications data model:

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
    [coder encodeObject:_myTextView.text forKey:@"UnsavedText"];
    [super decodeRestorableStateWithCoder:coder];
}

-(void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
    _myTextView.text = [coder decodeObjectForKey:@"UnsavedText"];
    [super encodeRestorableStateWithCoder:coder];
}

Note that it is important to call the corresponding method in the superclass before returning from the above methods.

Understanding the Restoration Process

Although UIKit handles the task of remembering which view controllers are to be restored, the actual recreation of those objects is the responsibility of the application code. Restoration can either be performed within the application delegate class, or by implementing a restoration class for the view controller.

Restoration classes are useful for restoring view controllers that are not stored in a storyboard file. When attempting to restore a specific view controller, UIKit will first check whether or not a restoration class exists for that controller. If one exists, UIKit instantiates it and calls its viewControllerWithRestorationIdentifierPath method and expects the method to create the corresponding view controller object and return it. If the method returns a nil value, however, UIKit assumes the view controller is not to be restored.

In order for a class to qualify as a restoration class it must implement the UIViewControllerRestoration protocol. Typically, a view controller not stored in a storyboard file will implement this protocol and act as its own restoration class.

When an application is started and UIKit finds a file containing a preserved state, UIKit makes a call to the application:willFinishLaunchingWithOptions method of the application delegate class. This will be followed by repeated calls to an application delegate method named viewControllerWithRestorationIdentifierPath. This method will be called once for each saved view controller for which a restoration class cannot be found. Passed through as an argument to this method is an array identifying the restoration path explicitly referencing the view controller which is to be recreated.

This restoration path is essentially made up from the restoration IDs of the elements in the view controller hierarchy, starting with the root controller and walking down the tree to the view controller UIKit is looking for. Consider, for example, the view hierarchy illustrated in Figure 64-2 where each tree node is labeled using the restoration ID of the corresponding view or view controller object.


iOS 7 State Restoration View Hierarchy

Figure 64-2


In the event that UIKit needs viewController2 to be recreated, the restoration path passed to the application delegate would be:

tabController1 / navController1 / viewController2

The application delegate method now has two choices. Either it can recreate the view controller object and return it to UIKit or it can return a nil value. To recreate a view controller, the application delegate can either instantiate the appropriate view controller class and return it or, if the view controller is stored in a storyboard file, load it and create it from there.

If the viewControllerWithRestorationIdentifierPath: returns a nil value, UIKit will continue looking for the view controller object. UIKit will first check to make sure the view controller object has not already been created as part of the application’s initialization process. Failing that, if the view controller resides in a storyboard file, UIKit will find it implicitly and load and recreate it automatically.

Saving General Application State

So far in this chapter we have focused exclusively on saving the state of the user interface in terms of views and view controllers. There will also be situations where other data may be relevant to the state of the application but not directly associated with the user interface elements. In order to address this need, the following two methods may be implemented within the application delegate class:

  • application:willEncodeRestorableStateWithCoder
  • application:didEncodeRestorableStateWithCoder

The former method is called by UIKit at the start of the preservation process and is passed a reference to an NSCoder object into which state data may be stored. The application:didEncodeRestorableStateWithCoder method, on the other hand, is called when UIKit has completed the restoration process and is passed the NSCoder object into which general state data was previously stored.

Summary

A key part of providing an optimal user experience is to ensure that continuity of application appearance and behavior is maintained between one application launch instance and the next. Prior to iOS 6, this involved writing custom code to save and restore state. iOS 6, however, introduced new features in the UIKit Framework designed specifically to ease the implementation of state preservation and restoration in iOS applications. In this chapter, the basic concepts of state preservation have been covered. The next chapter, entitled An iOS 7 State Preservation and Restoration Tutorial, will work through a practical demonstration of how these concepts are implemented in an application.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book



PreviousTable of ContentsNext
Scheduling iOS 7 Local NotificationsAn iOS 7 State Preservation and Restoration Tutorial