iOS Reference Library Apple Developer
Search

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.

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 and iOS). Therefore, whichever platform you develop for, you should typically declare outlets using the Objective-C declared properties feature.

The general form of the declaration should be:

@property (attributes) IBOutlet UserInterfaceElementClass *anOutlet;

The behavior of outlets depends on the platform (see “Mac OS X” and “iOS”), so the actual declaration differs:

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

This pattern also works if you use the modern runtime and synthesize the instance variables, so it remains consistent across all situations.

Mac OS X

The File’s Owner of a nib file is by default 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 files 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.

iOS

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. If 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 viewDidUnload to invoke your accessor methods to set outlets to nil.

- (void)viewDidUnload {
    self.anOutlet = nil;
    [super viewDidUnload];
}

Note: On iOS prior to 3.0, the viewDidUnload method is not available. Instead you should set outlets to nil in setView:, as illustrated in this example:

- (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];
}
In addition, because of a detail of the implementation of dealloc in UIViewController, you should also set outlet variables to nil in dealloc:

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




Last updated: 2010-06-24

Did this document help you? Yes It's good, but... Not helpful...