I’m a bit confused as to what happens exactly in Nib-based UIViewController
s. When generating a UIViewController
subclass, the template contains a very specific comment in the viewDidUnload
method:
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
Which subviews does this apply to?
viewDidLoad
? (I’d say yes)initWithNibName
? (I’d say no)IBOutlet
s that reference objects in the Nib?If I use the view controller like this:
MyViewController *controller = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
In this case I suppose it doesn’t matter much whether instance variables that hold references to subview are released in viewDidUnload
or dealloc
since dealloc
should get called as soon as the view controller is popped off the stack so I might as well do as Apple says and release instance variables on viewDidUnload
instead of dealloc
.
But suppose I used MyViewController
as an instance variable that may be pushed multiple times:
if(self.myViewController == nil) {
self.myViewController = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
}
// Change some state which should be reflected in the view
self.myViewController.someProperty = someValue;
[self.navigationController pushViewController:self.myViewController animated:YES];
What happens in MyViewController
if I release an IBOutlet
in viewDidUnload
? Can I count on having a new reference to it on the next viewDidLoad
?
In other words: what happens to the view itself after viewDidUnload
? Is it released and re-loaded from the Nib if the controller is pushed again? Or does the view remain in memory? And if so, do the outlets get re-set before viewDidLoad
?
If either the view remains in memory and the outlets are re-set before viewDidLoad
(or is reloaded each time the controller is pushed), I suppose it would be correct to release the outlets in viewDidUnload
(even though in the first case it does not matter). But otherwise (specifically if the view remains in memory and the outlets are NOT re-set), releasing the subviews in viewDidUnload
is wrong for the use case I presented, am I correct?
From the UIViewController documentation, Memory Management section:
When a low-memory warning occurs, the
UIViewController
class purges its views if it knows it can reload or recreate them again later. If this happens, it also calls theviewDidUnload
method to give your code a chance to relinquish ownership of any objects that are associated with your view hierarchy, including objects loaded with the nib file, objects created in yourviewDidLoad
method, and objects created lazily at runtime and added to the view hierarchy. Typically, if your view controller contains outlets (properties or raw variables that contain theIBOutlet
keyword), you should use theviewDidUnload
method to relinquish ownership of those outlets or any other view-related data that you no longer need.
So not only can you release your outlets in viewDidUnload
, this is the preferred and recommended way.
And yes, you can count on having your outlets point to valid objects when viewDidLoad
is called. Again from the UIViewController documentation, on viewDidLoad
:
This method is called after the view controller has loaded its associated views into memory.