Apple Watch Interface Navigation
- Interface Controllers and Storyboard
- Navigating between Interface Controllers
- Summary
- It’s really hard to design products by focus groups. A lot of times, people don’t know what they want until you show it to them.
- Steve Jobs
In Chapter 1, “Getting Started with WatchKit Programming,” you learned about the various specifications and features of the Apple Watch. You also had the chance to use Xcode to create a simple iPhone project that supports the Apple Watch. You then used the Apple Watch Simulator to test the application. In this chapter, you dive into how your Apple Watch application navigates between multiple screens.
Interface Controllers and Storyboard
As you learned in Chapter 1, the user interface of your Apple Watch application is encapsulated in a storyboard file. Within the storyboard file, you have an Interface Controller that represents a screen on the Apple Watch. In this section, let’s create a project so that we can examine the storyboard in more detail:
- Using Xcode, create a Single View Application project and name it LifeCycle.
Add the WatchKit App target to the project. Uncheck the option Include Notification Scene so that we can keep the WatchKit project to a bare minimum.
Once the target is added to the project, select the Interface.storyboard file located within the LifeCycle WatchKit App group (see Figure 2.1). This opens the file using the Storyboard Editor.
Figure 2.1 Editing the storyboard file
Select the Interface Controller and view its Identity Inspector window (see Figure 2.2). The Class is set to InterfaceController, which means that it is represented by a Swift class named InterfaceController.
Figure 2.2 The Interface Controller is represented by a Swift class named InterfaceController
View its Attributes Inspector window and observe that the Is Initial Controller attribute is checked (see Figure 2.3). This attribute indicates that, when the application is loaded, this is the default Interface Controller that will be displayed.
Figure 2.3 The Is Initial Controller attribute indicates that the current Interface Controller will be displayed when the application loads
Lifecycle of an Interface Controller
As you have seen in the previous section and in Chapter 1, an Interface Controller is connected to a Swift class located in the WatchKit Extension group of the project. In this example, this Swift class is named InterfaceController.swift. It has the following content:
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
}
override func willActivate() {
// This method is called when watch view controller is about to
// be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
}
Specifically, it has three key methods:
- awakeWithContext:—The system calls this method at initialization time, passing it any contextual data from a previous Interface Controller. You should use this method to initialize and to prepare your UI for display, as well as to obtain any data that is passed to it from another Interface Controller (you will learn how this is done in the later section on passing data).
- willActivate—This method is called by the system when the Interface Controller is about to be displayed. You should use this method to make some last-minute changes to your UI and to refrain from performing any tasks that initialize the UI—these should be done in the awakeWithContext method.
- didDeactivate—This method is called when the Interface Controller is no longer onscreen. You should use this method to perform cleanup operations on your Interface Controller, such as invalidating timers or saving state-related information.
Besides the three methods just discussed, you can also add an initializer to the Interface Controller class:
override init() { super.init() }
You can also perform initialization for your Interface Controller in this initializer, but you should leave the bulk of the UI initialization to the awakeWithContext method.
Let’s try an example to better understand the use of the various methods:
Add the following statements in bold to the InterfaceController.swift file:
import WatchKit import Foundation class InterfaceController: WKInterfaceController { override init() { super.init() println("In the init initializer") } override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) // Configure interface objects here. println("In the awakeWithContext event") } override func willActivate() { // This method is called when watch view controller is about to be // visible to user super.willActivate() println("In the willActivate event") } override func didDeactivate() { // This method is called when watch view controller is no longer // visible super.didDeactivate() println("In the didDeactivate event") } }
Run the application on the iPhone 6 Simulator. When the application is loaded onto the Apple Watch Simulator, you should see the statements printed out in the Output Window in Xcode, as shown in Figure 2.4. Observe that the init, awakeWithContext:, and willActivate methods are fired when the Interface Controller is loaded.
Figure 2.4 Examining the events that are fired when an Interface Controller is loaded
With the Apple Watch Simulator selected, select Hardware | Lock to lock the Apple Watch. Observe the output in the Output window (see Figure 2.5). Observe that the didDeactivate method is now executed.
Figure 2.5 Examining the event that is fired when an Interface Controller is deactivated