6
View Controllers

In Chapter 5, you created a view hierarchy (a scroll view with two subviews) and presented it on screen by explicitly adding the scroll view as a subview of the application’s window. It is more common to do this using a view controller.

A view controller is an instance of a subclass of UIViewController. A view controller manages a view hierarchy. It is responsible for creating view objects that make up the hierarchy, for handling events associated with the view objects in its hierarchy, and for adding its hierarchy to the window.

In this chapter, you will create an application named HypnoNerd. In HypnoNerd, the user will be able to switch between two view hierarchies – one for being hypnotized and the other for setting a reminder for hypnosis on a future date.

Figure 6.1  The two faces of HypnoNerd

The two faces of HypnoNerd

To make this happen, you are going to create two UIViewController subclasses: BNRHypnosisViewController and BNRReminderViewController. You will use the UITabBarController class to allow the user to switch between the view hierarchies of the two view controllers.

Create a new iOS project (Command-Shift-N) from the Empty Application template. Name this project HypnoNerd and configure the project as shown in Figure 6.2.

Figure 6.2  Creating a new project

Creating a new project

You are going to reuse the BNRHypnosisView class from Hypnosister in this project.

In Finder, locate the directory containing your Hypnosister project. Drag the BNRHypnosisView.h and BNRHypnosisView.m files from Finder into the project navigator in Xcode.

In the sheet that appears, check the box to Copy items into destination group’s folder (if needed) and the box next to the HypnoNerd target and click Finish (Figure 6.3).

Figure 6.3  Copy files to HypnoNerd

Copy files to HypnoNerd

This will create copies of the two files and add them to HypnoNerd’s directory on the filesystem and to the HypnoNerd project.

Subclassing UIViewController

From the File menu, select NewFile... From the iOS section, select Cocoa Touch and then choose Objective-C class. Click Next.

Name this class BNRHypnosisViewController and choose NSObject as its superclass (Figure 6.4). Click Next and save the files to finish creating the class.

Figure 6.4  Creating BNRHypnosisViewController

Creating BNRHypnosisViewController

You created the class with the NSObject template to start with the simplest template possible. By starting simple, you get the chance to see how the pieces work together.

Open BNRHypnosisViewController.h and change the superclass to UIViewController.

@​i​n​t​e​r​f​a​c​e​ ​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​:​ ​N​S​O​b​j​e​c​t​
@​i​n​t​e​r​f​a​c​e​ ​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​:​ ​U​I​V​i​e​w​C​o​n​t​r​o​l​l​e​r​

@​e​n​d​

The view of a view controller

As a subclass of UIViewController, BNRHypnosisViewController inherits an important property:

@​p​r​o​p​e​r​t​y​ ​(​n​o​n​a​t​o​m​i​c​,​ ​s​t​r​o​n​g​)​ ​U​I​V​i​e​w​ ​*​v​i​e​w​;​

This property points to a UIView instance that is the root of the view controller’s view hierarchy. When the view of a view controller is added as a subview of the window, the view controller’s entire view hierarchy is added.

Figure 6.5  Object diagram for HypnoNerd

Object diagram for HypnoNerd

A view controller’s view is not created until it needs to appear on the screen. This optimization is called lazy loading, and it can often conserve memory and improve performance.

There are two ways that a view controller can create its view hierarchy:

  • programmatically, by overriding the UIViewController method loadView.

  • in Interface Builder, by loading a NIB file. (Recall that a NIB file is the file that gets loaded and the XIB file is what you edit in Interface Builder.)

Because the view hierarchy of BNRHypnosisViewController consists of only one view, it is a good candidate for being created programmatically.

Creating a view programmatically

Open BNRHypnosisViewController.m and import the header file for BNRHypnosisView. Then override loadView to create a screen-sized instance of BNRHypnosisView and set it as the view of the view controller.

#​i​m​p​o​r​t​ ​"​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​.​h​"​
#​i​m​p​o​r​t​ ​"​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​.​h​"​

@​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​

-​ ​(​v​o​i​d​)​l​o​a​d​V​i​e​w​
{​
 ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​ ​v​i​e​w​
 ​ ​ ​ ​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​ ​*​b​a​c​k​g​r​o​u​n​d​V​i​e​w​ ​=​ ​[​[​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​

 ​ ​ ​ ​/​/​ ​S​e​t​ ​i​t​ ​a​s​ ​*​t​h​e​*​ ​v​i​e​w​ ​o​f​ ​t​h​i​s​ ​v​i​e​w​ ​c​o​n​t​r​o​l​l​e​r​
 ​ ​ ​ ​s​e​l​f​.​v​i​e​w​ ​=​ ​b​a​c​k​g​r​o​u​n​d​V​i​e​w​;​
}​

@​e​n​d​

When a view controller is created, its view property is nil. If a view controller is asked for its view and its view is nil, then the view controller is sent the loadView message.

The next step is to add the view hierarchy of the BNRHypnosisViewController to the application window so that it will appear on screen to users.

Setting the root view controller

There is a convenient method for adding a view controller’s view hierarchy to the window: UIWindow’s setRootViewController:. Setting a view controller as the rootViewController adds that view controller’s view as a subview of the window. It also automatically resizes the view to be the same size as the window.

In BNRAppDelegate.m, import BNRHypnosisViewController.h at the top of the file. Then create an instance of BNRHypnosisViewController and set it as the rootViewController of the window.

#​i​m​p​o​r​t​ ​"​B​N​R​A​p​p​D​e​l​e​g​a​t​e​.​h​"​
#​i​m​p​o​r​t​ ​"​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​.​h​"​

@​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​B​N​R​A​p​p​D​e​l​e​g​a​t​e​

-​ ​(​B​O​O​L​)​a​p​p​l​i​c​a​t​i​o​n​:​(​U​I​A​p​p​l​i​c​a​t​i​o​n​ ​*​)​a​p​p​l​i​c​a​t​i​o​n​
 ​ ​ ​ ​d​i​d​F​i​n​i​s​h​L​a​u​n​c​h​i​n​g​W​i​t​h​O​p​t​i​o​n​s​:​(​N​S​D​i​c​t​i​o​n​a​r​y​ ​*​)​l​a​u​n​c​h​O​p​t​i​o​n​s​
{​
 ​ ​ ​ ​s​e​l​f​.​w​i​n​d​o​w​ ​=​ ​[​[​U​I​W​i​n​d​o​w​ ​a​l​l​o​c​]​ ​i​n​i​t​W​i​t​h​F​r​a​m​e​:​[​[​U​I​S​c​r​e​e​n​ ​m​a​i​n​S​c​r​e​e​n​]​ ​b​o​u​n​d​s​]​]​;​
 ​ ​ ​ ​/​/​ ​O​v​e​r​r​i​d​e​ ​p​o​i​n​t​ ​f​o​r​ ​c​u​s​t​o​m​i​z​a​t​i​o​n​ ​a​f​t​e​r​ ​a​p​p​l​i​c​a​t​i​o​n​ ​l​a​u​n​c​h​
 ​ ​ ​ ​
 ​ ​ ​ ​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​*​h​v​c​ ​=​ ​[​[​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​

 ​ ​ ​ ​s​e​l​f​.​w​i​n​d​o​w​.​r​o​o​t​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​=​ ​h​v​c​;​
 ​ ​ ​ ​
 ​ ​ ​ ​s​e​l​f​.​w​i​n​d​o​w​.​b​a​c​k​g​r​o​u​n​d​C​o​l​o​r​ ​=​ ​[​U​I​C​o​l​o​r​ ​w​h​i​t​e​C​o​l​o​r​]​;​
 ​ ​ ​ ​[​s​e​l​f​.​w​i​n​d​o​w​ ​m​a​k​e​K​e​y​A​n​d​V​i​s​i​b​l​e​]​;​
 ​ ​ ​ ​r​e​t​u​r​n​ ​Y​E​S​;​
}​

The view of the root view controller appears at the start of the run of the application. Thus, the window asks for it when setting the view controller as its rootViewController.

Given what you learned in Chapter 4, you can imagine what the core of setRootViewController: looks like:

-​ ​(​v​o​i​d​)​s​e​t​R​o​o​t​V​i​e​w​C​o​n​t​r​o​l​l​e​r​:​(​U​I​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​*​)​v​i​e​w​C​o​n​t​r​o​l​l​e​r​
{​
 ​ ​ ​ ​/​/​ ​G​e​t​ ​t​h​e​ ​v​i​e​w​ ​o​f​ ​t​h​e​ ​r​o​o​t​ ​v​i​e​w​ ​c​o​n​t​r​o​l​l​e​r​
 ​ ​ ​ ​U​I​V​i​e​w​ ​*​r​o​o​t​V​i​e​w​ ​=​ ​v​i​e​w​C​o​n​t​r​o​l​l​e​r​.​v​i​e​w​;​

 ​ ​ ​ ​/​/​ ​M​a​k​e​ ​a​ ​f​r​a​m​e​ ​t​h​a​t​ ​f​i​t​s​ ​t​h​e​ ​w​i​n​d​o​w​'​s​ ​b​o​u​n​d​s​
 ​ ​ ​ ​C​G​R​e​c​t​ ​v​i​e​w​F​r​a​m​e​ ​=​ ​s​e​l​f​.​b​o​u​n​d​s​;​
 ​ ​ ​ ​r​o​o​t​V​i​e​w​.​f​r​a​m​e​ ​=​ ​v​i​e​w​F​r​a​m​e​;​

 ​ ​ ​ ​/​/​ ​I​n​s​e​r​t​ ​t​h​i​s​ ​v​i​e​w​ ​a​s​ ​w​i​n​d​o​w​'​s​ ​s​u​b​v​i​e​w​
 ​ ​ ​ ​[​s​e​l​f​ ​a​d​d​S​u​b​v​i​e​w​:​r​o​o​t​V​i​e​w​]​;​

 ​ ​ ​ ​/​/​ ​U​p​d​a​t​e​ ​t​h​e​ ​i​n​s​t​a​n​c​e​ ​v​a​r​i​a​b​l​e​
 ​ ​ ​ ​_​r​o​o​t​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​=​ ​v​i​e​w​C​o​n​t​r​o​l​l​e​r​;​

}​

At the beginning of this implementation, the BNRHypnosisViewController is asked for its view. Because the BNRHypnosisViewController has just been created, its view is nil. So it is sent the loadView message that creates its view.

Build and run the application. HypnoNerd looks a lot like Hypnosister did. Under the hood, however, it is quite different. You are using a view controller to present the BNRHypnosisView instead of adding the view object itself to the window. This adds a layer of complexity, which, as you will see by the end of the chapter, gives you power and flexibility to do neat things.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset