View Controller Basics
Implementation Checklist for Custom View Controllers
1. For any custom view controllers you create, there are several tasks that you should always handle:
You must configure the view to be loaded by your view controller;
You must decide which orientations your view controller supports;
You must clean up the memory that is managed by your view controller;
Anatomy of a Custom View Controller

Understanding the View Management Cycle
1. The load cycle occurs whenever some part of your application asks the view controller for a pointer to its view object and that object is not currently in memory. When that happens, the view controller loads the view into memory and stores a pointer to the view for future reference.
2. If your application receives a low-memory warning at some point in the future, the view controller may subsequently try to unload the view. During the unload cycle, the view controller attempts to release its view object and return the view controller to its initial viewless state. If it is able to release the view, the view controller remains without a view object until the view is once again requested, at which point the load cycle begins again.
3. The steps that occur during the load cycle are as follows:
(1) Some part of your application asks for the view in the view controller’s view property.
(2) If the view is not currently in memory, the view controller calls its loadView method.
(3) The loadView method does one of the following:
If you override this method, your implementation is responsible for creating all necessary views andassigning a non-nil value to the view property.
If you do not override this method, the default implementation uses the nibName and nibBundle properties of the view controller to try to load the view from the specified nib file.
If the specified nib file is not found, it looks for a nib file whose name matches the name of the view controller class and loads that file.
If no nib file is available, the method creates an empty UIView object and assigns it to the view property.
(4) The view controller calls its viewDidLoad method to perform any additional load-time tasks.
4. The steps that occur during the unload cycle are as follows:
(1) The application receives a low-memory warning from the system.
(2) Each view controller calls its didReceiveMemoryWarning method:
If you override this method, you should use it to release any custom data that your view controller object no longer needs. You should not use it to release your view controller’s view. You must call super at some point in your implementation to perform the default behavior.
The default implementation releases the view only if it determines that it is safe to do so.
If you do override didReceiveMemoryWarning, always call super to give the inherited version of the method a chance to release the view.
(3) If the view controller releases its view, it calls its viewDidUnload method. You can override this method to perform any additional cleanup required for your views and view hierarchy.
Defining a Custom View Controller Class
1. Creating the View in Interface Builder
There are two ways to configure a nib file for use with a view controller:
- Create a detached nib file by storing the view in a nib file by itself.
- Create an integrated nib file by storing both the view and view controller in the same nib file.
- Set the class name of the File’s Owner placeholder to your view controller class.
- Make sure the view outlet of the File’s Owner placeholder is connected to the top-level View object in the nib file.
- Configure the view itself and add any subviews you need to display your application’s content.
-
Save the nib file.

1. If your application has only one screen, you can include both the views for that screen and the view controller that manages them in the same nib file. Storing views and custom view controller objects in the same nib file is generally not recommended because it often prevents the system from unloading the views in low-memory situations. However, if the view itself is never going to be unloaded, including it in the same nib file as its view controller object might make the most sense.

Configuring the View Display Attributes in Interface Builder

Creating the View Programmatically
- Create a root view object that is sized to fit the screen.
- Create any additional subviews and add them to the root view.
b. Add the view to a parent view using the addSubview: method.
c. Release the view by calling its release method.
- Assign the root view to the view property of your view controller.
- Release the root view.
- (void)loadView {
self.wantsFullScreenLayout = YES;
MetronomeView *view = [[MetronomeView alloc]
initWithFrame:[UIScreen mainScreen].applicationFrame];
view.metronomeViewController = self;
self.view = view;
self.metronomeView = view;
[view release];
}
Cleaning Up After Unloading a View
The dealloc method
The viewDidUnload method
Managing Memory Efficiently

Managing a View Controller’s Interface Orientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if ((orientation == UIInterfaceOrientationPortrait) ||
(orientation == UIInterfaceOrientationLandscapeLeft))
return YES;
return NO;
}
If the view managed by your view controller supports orientations other than the default portrait orientation, you must override the shouldAutorotateToInterfaceOrientation: method and indicate which orientations your view supports.
Show or hide views that are specific to a particular orientation.
Adjust the position or size of views based on the new orientation.
Update other parts of your application to reflect the orientation change.
sequence of events occurs:
- The window detects that a change in the device orientation has occurred.
- The window looks for an appropriate view controller and calls itsshouldAutorotateToInterfaceOrientation: method to determine if it supports the new orientation.For example, the tab bar controller allows orientation changes only if all of its managed view controllers support the new orientation.
- If the new orientation is supported, the window calls the view controller’swillRotateToInterfaceOrientation:duration: method.Container view controllers forward this message on to the currently displayed custom view controller. You can override this method in your custom view controllers to hide views or make other changes to your view layout before the interface is rotated.
- The window adjusts the bounds of the view controller’s view. This causes each view in the view hierarchy to be resized based on its autoresizing mask.
- The window calls the view controller’s didRotateFromInterfaceOrientation: method.Container view controllers forward this message to the currently displayed custom view controller. This marks the end of the rotation process. You can use this method to show views, change the layout of views, or make other changes to your application.



Creating an Alternate Landscape Interface
2. In order to support an alternate landscape interface, you have to do the following:
- Implement two view controller objects:
- One should present a portrait-only interface.
- One should present a landscape-only interface.
- Register for the UIDeviceOrientationDidChangeNotification notification. In your handler method, present or dismiss the alternate view controller based on the current device orientation.
@implementation PortraitViewController
- (id)init
{
self = [super initWithNibName:@"PortraitView" bundle:nil];
if (self)
{
isShowingLandscapeView = NO;
self.landscapeViewController = [[[LandscapeViewController alloc]
initWithNibName:@"LandscapeView" bundle:nil] autorelease];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
return self;
}
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) &&
!isShowingLandscapeView)
{
[self presentModalViewController:self.landscapeViewController
animated:YES];
isShowingLandscapeView = YES;
}
else if (UIDeviceOrientationIsPortrait(deviceOrientation) &&
isShowingLandscapeView)
{
[self dismissModalViewControllerAnimated:YES];
isShowingLandscapeView = NO;
}
}
Tips for Implementing Your Rotation Code
- Disable event delivery temporarily during rotations. Disabling event delivery for your views prevents unwanted code from executing while an orientation change is in progress.
- Store the visible map region. If your application contains a map view, save the visible map region value prior to the beginning of rotations. When the rotations finish, use the saved value as needed to ensure that the displayed region is approximately the same as before.
- For complex view hierarchies, replace your views with a snapshot image. If animating large numbers of views is causing performance issues, temporarily replace those views with an image view containing an image of the views instead. Once the rotations are complete, reinstall your views and remove the image view.
- Reload the contents of any visible tables after a rotation.Forcing a reload operation when the rotations are finished ensures that any new table rows exposed are filled appropriately.
- Use rotation notifications to update your application’s state information. If your application uses the current orientation to determine how to present content, use the rotation methods of your view controller (or the corresponding device orientation notifications) to note those changes and make any necessary adjustments.