2
votes

For a view controller, any outlets that you set in Interface Builder must be released and set to nil in viewDidUnload, and must also be released in dealloc.

(see: When should I release objects in viewDidUnload rather than in dealloc?)

One of the most important reasons for implementing [viewDidUnload] is that UIViewController subclasses commonly also contain owning references to various subviews in the view hierarchy. These properties could have been set through IBOutlets when loading from a nib, or programmatically inside loadView [emphasis added], for instance.

My question is, do we really need to implement viewDidUnload for subviews in the view hierarchy that are created programmatically in loadView (without Interface Builder)?

3

3 Answers

5
votes

It depends how you created them and if you need to reference them elsewhere.

For example:

- (void)loadView
{
    [super loadView];

    UIButton *someButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    someButton.frame = CGRectMake(0, 0, 50, 50);
    [self.view addSubview: someButton];
}

In the above case you would not need to implement viewDidUnload because someButton is autoreleased within loadView.

Another example:

- (void)loadView
{
    [super loadView];

    self.someButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    someButton.frame = CGRectMake(0, 0, 50, 50);
    [self.view addSubview: someButton];
}

In this example you would want to use viewDidUnload, as you have another reference to someButton hanging around. You want viewDidUnload to release that button and reset the reference so you don't improperly use it as well as free up the memory. In this case you would also want to release the button in the dealloc method as well, in case viewDidUnload is never called.

2
votes

You certainly should. If you look through Apple samples, however, you'll find that sometimes they just use dealloc. If you know your object will get deallocated at some reasonable time after use, I think this is perfectly reasonable. I follow this pattern, however, as viewDidUnload might not be called in certain exceptional cases. I do not actually call the release method such a long name:

-(void)releaseRetainedXibAndViewDidLoadObjects
{
    self.myLabel = nil;
    self.myImage = nil;
}

-(void)viewDidUnload
{
    [super viewDidUnload];
    [self releaseRetainedXibAndViewDidLoadObjects];
}

-(void)dealloc
{
    self.myObject = nil;
    [self releaseRetainedXibAndViewDidLoadObjects];
    [super dealloc];
}

You could even do this from an application specific view controller object that your classes subclass to simplify matters.

0
votes

Do it in your dealloc method. There is no guarantee that viewDidUnload will be invoked. It is typically only invoked when the controller needs to unload the view, e.g. when there's a memory warning. On the other hand, the init/dealloc pairing will always be invoked.