Chapter 7
UIView and UIViewController

Key Skills & Concepts

• Understanding the UIView and UIViewController

• Creating a single view application using the View-based Application template

• Creating a single view application using the Window-based Application template

• Understanding an application delegate’s root view

• Setting an application’s root view in Interface Builder

• Setting an application’s root view using code

• Understanding UIView life cycle methods

UIViews are how the iOS displays information on the screen. The UIView class is responsible for displaying a rectangular area on the screen. The UIViewController manages the UIView and is responsible for handling the view’s logic. The UIViewController is the glue between the view—the UIView—and your data classes—the model.

There are many UIView subclasses you might work with while developing an iOS application. In fact, every graphical component you use on an iOS graphical user interface (GUI) is a UIView subclass. Technically speaking, everything is a view. But typically, when documentation or some other material refers to a “view,” it is referring to a content view. A content view is a view that has a view controller and is responsible for presenting a screen’s worth of user interface.

The UIView Class

The UIView’s responsibilities are drawing to the screen and handling events associated with a user’s interaction with an application. A UIView has an associated UIViewController. The UIViewController manages the view. The view controller loads and unloads its associated views, manages views, and handles application life cycle events for its views.

Every graphical iOS control you use in Interface Builder is a UIView subclass. Table 7-1 lists the UIView subclasses. Notice that UIScrollView and UIControl both have further subclasses listed in the table’s second column.

UIViews function as containers, controls, displays, alerts, action sheets, and navigation controls, and also as the application’s window. In future chapters, we’ll cover most of these UIView types. This chapter limits itself to a simple display view and associated view controller.

Image

Table 7-1 UIView Subclasses in UIKit

The UIViewController Class

The UIViewController manages UIViews. It is responsible for creating, displaying, hiding, and destroying a view. The UIViewControl is also responsible for responding to a view’s life cycle events, handling orientation, and serving as a bridge between your application’s view and model. The view controller is your application’s controller in the model-view-controller design pattern.

View-Based Application Template

The easiest route to creating a single view application is using Xcode’s View-based Application template. This template creates a single view and a view controller for managing the view. While the View-based application is not as useful as Xcode’s other project templates, it is helpful here, as it generates the simplest iOS graphical application and provides a straightforward UIView and UIViewController example. In the next task, you will generate an application using this template. But, before continuing, first we will review IBOutlets and IBActions.

IBOutlet and IBAction

You have already used IBOutlets and IBActions in previous chapters. Without really knowing what they are, you probably already have a good idea of what they accomplish; outlets and actions are how you connect things in a nib with things outside a nib. An outlet connects an instance variable outside a nib to an object in a nib.

IBOutlet is a preprocessor directive, evaluates to void, and is ignored by the compiler, but all you really need to know is that IBOutlet is how Interface Builder knows the variable was created for its use. When you change the class of an object, Interface Builder scans the class for IBOutlets and knows those variables are intended as outlets. You can then easily connect your graphical component to the variable, as Interface Builder adds the outlets to the inspector automatically for you to select. Note, though, Interface Builder doesn’t connect the outlets to anything; it just adds them. You are responsible for adding any connections.

Actions are messages sent from objects in the nib to methods outside the nib. You define an action in your code using the IBAction keyword. Like IBOutlet, it’s a preprocessor directive and evaluates to void. You define an action in your code using the IBAction keyword. Also, like IBOutlet, when you assign a class to a control in Interface Builder, it scans the class for IBActions and adds them to the inspector for you to select. You can then connect user interface events to a specific method in your code. Note that a method designated as an action must not return a value, as the preprocessor replaces IBAction with void, and so all the compiler sees is void. An action also takes a single parameter, sender. The sender is the id of the control calling the action. So if a UIButton instance called an IBAction named changeLabelValue, the sender would be the pointer to the UIButton.

-(IBAction) changeLabelValue: (id) sender;

IBOutlet and IBAction don’t require much explanation, as you use these two directives so frequently they become second nature. Any instance variable external to Interface Builder that must communicate with a control in Interface Builder must be an IBOutlet. Any method that must be called from a control in Interface Builder must be an IBAction.

Try This: Using a View-Based Application Template

1. Create a new View-based Application using the template. Name the project SimpleView.

2. Expand the Classes group and notice XCode created the SimpleViewViewController class for you. Expand Resources and notice the template generated a separate nib, SimpleViewViewController.xib, for the SimpleViewViewController.

3. Open SimpleViewViewController.h and add a label and method for changing the label’s value. Make the label an IBOutlet and the method an IBAction (Listing 7-1).

Listing 7-1 SimpleViewViewController.h

#import <UIKit/UIKit.h>
@interface SimpleViewViewController : UIViewController {
UILabel * theLabel;
}
@property (nonatomic, retain) IBOutlet UILabel *theLabel;
-(IBAction) changeLabelValue: (id) sender;
@end

4. Open SimpleViewViewController.m and add the IBOutlet and IBAction definitions (Listing 7-2).

Listing 7-2 SimpleViewViewController.m

#import "SimpleViewViewController.h"
@implementation SimpleViewViewController
@synthesize theLabel;
-(IBAction) changeLabelValue : (id) sender {
  [theLabel setText:@"Hello World."];
  UIButton *theBut = sender;
  NSLog(theBut.currentTitle);
  theBut.enabled = NO;
  [theBut setTitle:@"Pressed Already" forState:
UIControlStateDisabled];
}
-(void)dealloc {
  [theLabel release];
  [super dealloc];
}
@end

5. Select SimpleViewViewController.xib to display it in Interface Builder and change the view’s color. Add a UILabel and a UIButton to the UIView.

6. Notice that SimpleViewViewController is the File’s Owner. Connect SimpleViewViewController’s the Label outlet to the label.

7. Connect SimpleViewViewController’s changeTheLabel action to the button. Select Touch Up Inside.

8. Save your changes.

9. Click Build And Go to run the application.

Take a moment to examine what the View-based Application template did for you. It created the SimpleViewViewController.xib and it also created a UIViewController subclass, SimpleViewViewController, by creating the SimpleViewViewController.h and SimpleViewViewController.m files. Moreover, it added the controller to the delegate (Listing 7-3).

Listing 7-3 SimpleViewAppDelegate.h

#import <UIKit/UIKit.h>
@class SimpleViewViewController;
@interface SimpleViewAppDelegate : NSObject <UIApplicationDelegate> {
  UIWindow *window;
  SimpleViewViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain)    IBOutlet SimpleViewViewController
*viewController;
@end

In the delegate, the template created the application’s window and view controller as outlets (Listings 7-3 and 7-4). In the delegate’s applicationDidFinishLaunchingWithOptions: method, the template added the view controller’s view to the window and then displayed the window. Notice that nowhere does the code allocate or initialize its window or view controller. Instead, Info.plist specifies that MainWindow.xib is the application’s main nib, so it knows to load MainWindow.xib and the nib handles window and view controller initialization.

Listing 7-4 SimpleViewAppDelegate.m

#import "SimpleViewAppDelegate.h"
#import "SimpleViewViewController.h"
@implementation SimpleViewAppDelegate
@synthesize window;

@synthesize viewController;
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [window addSubview:viewController.view];
  [window makeKeyAndVisible];
  return YES;
}
-(void)dealloc {
  [viewController release];
  [window release]; [super dealloc];
}
@end

In the MainWindow nib, the template set the nib’s file’s owner to UIApplication. The template set SimpleViewAppDelegate as the application’s delegate and set the delegate’s window to the window in MainWindow.xib.

The template also added a view controller to MainWindow.xib and set it as the delegate’s root view controller. Every delegate must have a root view controller. The root view controller in MainWindow.xib comes from the SimpleViewViewController.xib, also created by the template.

The template created the UIView in its own xib, SimpleViewViewController.xib. It set SimpleViewViewController.xib’s file’s owner to SimpleViewViewController. It also set the controller’s view to the view in the xib.

Try This: Using a Window-Based Application Template

The View-based Application template hides many development details. If new to iOS programming, chances are you will not find that the View-based Application template helps clarify a UIView, a UIViewController, and their relationship. To help make their relationship clearer, you should understand what the View-based Application template accomplishes automatically.

Unlike a View-based Application template, a Window-based Application template requires understanding UIViews and UIViewControllers. When using the Window-based Application template, you must manually create a view and a view controller and wire them together. In this project, you create a single view application starting with a Window-based Application template. Creating a Window-based Application should solidify your understanding of the steps used by Xcode when creating a View-based application.

1. Create a new Window-based Application and name it SimpleWindow.

2. CTRL-click the Resources folder and select New File. Select User Interface under iOS and select View to create a new xib. Name the xib FirstViewController.xib.

3. Select File | New | New File. Add a UIViewController named FirstViewController. Xcode should create FirstViewController.h and FirstViewController.m. Be certain the check box to create a xib is not checked.

4. Open SimpleWindowAppDelegate.h and either import the FirstViewController or use an @class forward declaration. Add a UIViewController property to SimpleWindowAppDelegate.h so that it appears the same as Listing 7-5.

Listing 7-5 SimpleWindowAppDelegate.h

#import <UIKit/UIKit.h>
@class FirstViewController;
@interface SimpleWindowAppDelegate : NSObject <UIApplicationDelegate> {
 UIWindow *window;
 FirstViewController *rootViewController;
}
@property (nonatomic, retain) IBOutlet FirstViewController
*rootViewController;
@property (nonatomic, retain) IBOutlet UIWindow *window;
@end

5. Modify SimpleWindowAppDelegate.m so that it appears like Listing 7-6. Notice you must synthesize rootViewController and add its view to the window as a subview in the delegate’s applicationDidFinishLaunching: method.

Listing 7-6 SimpleWindowAppDelegate.m

#import "SimpleWindowAppDelegate.h"
#import "FirstViewController.h"
@implementation SimpleWindowAppDelegate
@synthesize window;
@synthesize rootViewController;
-(void)applicationDidFinishLaunching:(UIApplication *)application {
  [window addSubview:rootViewController.view];
  [window makeKeyAndVisible];
}
-(void)dealloc {
  [window release];
  [rootViewController release];
  [super dealloc];
}
@end

6. Select FirstViewController.xib to display it in Interface Builder. Select the File’s Owner and then select View | Utilities | Identity from the main menu. Notice that the class of the File’s Owner isn’t set.

7. Change its class to FirstViewController from the pull-down in the Object Identity Inspector pane.

8. Select the view, select Object Attributes in the Inspector pane, and change the view’s color.

9. Select the File’s Owner and click the Connections button in the Inspector pane, and then connect the view outlet to the view you added to the document window.

10. Save FirstViewController.xib and select MainWindow.xib to open it in Interface Builder.

11. Notice that there is no UIViewController or view set in the document window.

12. Scroll down in the list of objects and drag a view controller from the library to the editing pane. With the View Controller selected, go to the Object Identity Inspector pane and set its class to FirstViewController (Figure 7-1).

Image

Figure 7-1 Adding FirstViewController to Mainwindow.xib

13. In the Object Attributes Inspector pane, change its NIB Name to FirstViewController.

14. Select Simple Window App Delegate (one of the icons to the left of the editing pane). Select the Connections Inspector pane; notice the rootViewController outlet. Connect this to the view controller just added (Figure 7-2).

15. Save your changes.

16. Click Run to build and run your application. The view in FirstViewController.xib will be loaded into the window and displayed.

In Step 14, you connected the FirstViewController to the application’s delegate. This was an important step; it allowed the nib to set the delegate’s root view controller for you. The root view controller is the UIViewController that is first loaded by an application delegate. Remember, the application knew to load MainWindow.xib because it was in the application’s Info.plist. The application loaded MainWindow.xib, saw the FirstViewController object that was added to the document window, and saw that the delegate’s root view controller was set to FirstViewController. The application also knew the controller came from FirstViewController.xib. Because of the object, variable, and nib settings, the application knew to allocate and initialize a FirstViewController instance from FirstViewController.xib when loading MainWindow.xib. Because these relationships were established in Interface Builder, no manual code was necessary. This is how the View-based Application template builds a simple application, which you just duplicated manually using the Window-based application template.

Image

Figure 7-2 Setting Mainwindow.xib’s root view controller

NOTE
In this example, you manually created a xib and linked it to its associated view controller. Step 3 specifically instructed you not to check the check box that also created a xib; had you checked the check box, Xcode would have created a xib and automatically made most of these connections for you.

UIViewController and Application Life Cycle Events

UIViewController handles important life cycle events for its associated UIViews. Table 7-2 lists the UIViewController’s view life cycle instance methods.

Note that several methods in Table 7-2 are similar to an application delegate’s life cycle methods—for instance, the didReceiveMemoryWarning: method. Do not let this similarity confuse you; remember, life cycle methods in the view controller are for the controller’s associated view and not the application as a whole. Conversely, life cycle methods in the delegate are designed to handle events for the application as a whole.

Image

Table 7-2 UIViewController’s Instance Methods for View Life Cycle Management

Try This: Exploring Several Life Cycle Methods

1. Open the SimpleView project in Xcode.

2. Open SimpleViewController.m and note that Xcode generates many of the needed life cycle methods for you and then comments them. It even provides short descriptions of what each method does for you.

3. Add the life cycle methods in Listing 7-7 to the FirstViewController.m file. Because FirstViewController’s parent class, UIViewController, declares all these methods, you are not required to add a declaration for the methods in FirstViewController’s header file.

Listing 7-7 Life cycle methods added to FirstViewController.m

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)
interfaceOrientation {
return YES;
}

-(void)didReceiveMemoryWarning {
  NSLog(@"received memory warning....");
  [super didReceiveMemoryWarning];
}
-(void)viewDidLoad {
  NSLog(@"view did load...");
  [super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated {
  NSLog(@"view will appear...");
}
-(void)viewDidUnload {
  NSLog(@"view did unload...");
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)
fromInterfaceOrientation {
  NSLog(@"view rotated....");
}

4. Click Run to run the application.

5. When the application is running, turn the simulator sideways by selecting Hardware | Rotate right from the simulator’s menu (Figure 7-3).

6. Simulate a memory warning by selecting Hardware | Simulate Memory Warning.

7. Quit the application. The console’s output should appear similar to Listing 7-8.

Image

Figure 7-3 Running the application in landscape mode

Listing 7-8 Console’s logging

2010-08-26 23:47:10.931 SimpleView[42582:207] view did load...
2010-08-26 23:47:10.933 SimpleView[42582:207] view will appear...
2010-08-26 23:47:15.685 SimpleView[42582:207] view rotated....
2010-08-26 23:48:10.928 SimpleView[42582:207] Received simulated
memory warning.
2010-08-26 23:48:10.930 SimpleView[42582:207] received memory
warning....

Summary

This chapter discussed the UIView and UIViewController classes. When developing an iOS application, every content view should have its own nib. Remember, placing views in their own nib conserves memory by only loading the components needed to render the current view. The development pattern for creating a view is straightforward: Subclass a UIViewController in Xcode. Create the UIView in its own nib. Then, in the nib, connect the view to the view controller. To make your code easier to test and debug, keep the name consistent between the view, view controller, and nib. Implement any view-related life cycle methods you wish to handle in the view’s view controller. Keep your custom code to a minimum, though— remember, the controller’s job is to serve as glue code between your view and your model. Consider placing more advanced code in helper classes, and then have your controller use these helpers.

Now that you understand how to build each screen’s content, you can learn how to develop views that aggregate your individual views into a multiple-screen application. In the next chapter, you begin exploring multiview applications with the UITabBar and UITabBarController. After learning about tab bars, you move to the navigation controllers and then tables. These views let you aggregate content views into richer multiscreen applications.

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

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