< Previous PageNext Page > Hide TOC

Memory Management of Nib Objects

At various points in a Cocoa application’s runtime life, one or more nib files are loaded and the objects they contain are unarchived. Responsibility for releasing those objects when they are no longer needed depends on which platform you are developing for, and, on Mac OS X, which class your File’s Owner inherits from.

For a basic discussion of nib files and their memory management semantics, as well as definitions of nib-related terms such as “outlet,” “File’s Owner,” and “top-level object,” see Nib Files in Resource Programming Guide.

Contents:

Outlets
Mac OS X Desktop
iPhone


Outlets

When a nib file is loaded and outlets established, the nib-loading mechanism always uses accessor methods if they are present (on both Mac OS X desktop and iPhone). Therefore, whichever platform you develop for, you should typically declare outlets using the Objective-C declared properties feature as illustrated in this example:

@property (nonatomic, retain) IBOutlet UserInterfaceElementClass *anOutlet;

You should then either synthesize the corresponding accessor methods, or implement them according to the declaration, and then release the corresponding variable in dealloc.

Following this pattern gives you a consistent way of dealing with outlets regardless of platform. It ensures that object referenced by outlets remain valid for as long as is necessary, and that the general memory management semantics are made clear.

Mac OS X Desktop

The File’s Owner of a nib file is typically responsible for releasing the top-level objects in a nib file as well as any non-object resources created by the objects in the nib. The release of the root object of an object graph sets in motion the release of all dependent objects. The File’s Owner of an application’s main nib file (which contains the application menu and possibly other items) is the global application object NSApp. However, when a Cocoa application terminates, top level objects in the main nib do not automatically get dealloc messages just because NSApp is being deallocated (see also “Deallocating an Object”). In other words, even in the main nib file, you have to manage the memory of top-level objects.

The Application Kit offers a couple of features that help to ensure that nib objects are properly released:

So in general, you are responsible for releasing top-level objects in a nib file. But in practice, if your nib file’s owner is an instance of NSWindowController it releases the top-level object for you. If one of your objects loads the nib itself (and the owner is not an instance of NSWindowController), you can define outlets to each top-level object so that at the appropriate time you can release them using those references. If you don’t want to have outlets to all top-level objects, you can use the instantiateNibWithOwner:topLevelObjects: method of the NSNib class to get an array of a nib file’s top-level objects.

The issue of responsibility for nib object disposal becomes clearer when you consider the various kinds of applications. Most Cocoa applications are of two kinds: single window applications and document-based applications. In both cases, memory management of nib objects is automatically handled for you to some degree. With single-window applications, objects in the main nib file persist through the runtime life of the application and are released when the application terminates; however, dealloc is not guaranteed to be automatically invoked on objects from the main nib file when an application terminates. In document-based applications each document window is managed by an NSWindowController object which handles memory management for a document nib file.

Some applications may have a more complex arrangement of nib files and top-level objects. For example, an application could have multiple nib file with multiple window controllers, loadable panels, and inspectors. But in most of these cases, if you use NSWindowController objects to manage windows and panels or if you set the “released when closed” window attribute, memory management is largely taken care of. If you decide against using window controllers and do not want to set the “release when closed” attribute, you should explicitly free your nib file’s windows and other top-level objects when the window is closed. Also, if your application uses an inspector panel, (after being lazily loaded) the panel should typically persist throughout the lifetime of the application—there is no need to dispose of the inspector and its resources.

iPhone

Top-Level Objects

Objects in the nib file are created with a retain count of 1 and then autoreleased. As it rebuilds the object hierarchy, UIKit reestablishes connections between the objects using setValue:forKey:, which uses the available setter method or retains the object by default if no setter method is available. This means that (assuming you follow the pattern shown in “Outlets”) any object for which you have an outlet remains valid. If there are any top-level objects you do not store in outlets, however, you must retain either the array returned by the loadNibNamed:owner:options: method or the objects inside the array to prevent those objects from being released prematurely.

Memory Warnings

When a view controller receives a memory warning (didReceiveMemoryWarning), it should relinquish ownership of resources that are currently not needed and that can be recreated later if required. One such resource is the view controller's view itself. Assuming that it does not have a superview, the view is disposed of (in its implementation of didReceiveMemoryWarning, UIViewController invokes [self setView:nil]).

Since outlets to elements within the nib file are typically retained (see “Outlets”), however, even though the main view is disposed of, absent any further action the outlets are not disposed of. This is not in and of itself a problem—if and when the main view is reloaded, they will simply be replaced—but it does mean that the beneficial effect of the didReceiveMemoryWarning is reduced.

To ensure that you properly relinquish ownership of outlets, in your custom view controller class you can implement setView: as follows:

- (void)setView:(UIView *)aView {
    if (!aView) { // view is being set to nil
        // set outlets to nil, e.g.
        self.anOutlet = nil;
    }
    // Invoke super's implementation last
    [super setView:aView];
}

Unfortunately, this currently falls foul of another issue. Because UIViewController currently implements its dealloc method using the setView: accessor method (rather than simply releasing the variable directly), self.anOutlet = nil will be called in dealloc as well as in response to a memory warning. Assuming that the view controller is the only owner of the outlet, this will lead to a crash in dealloc.

You should therefore also set outlet variables to nil in dealloc:

- (void)dealloc {
    // release outlets and set outlet variables to nil
    [anOutlet release], anOutlet = nil;
    [super dealloc];
}


< Previous PageNext Page > Hide TOC


© 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-05-06)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.