Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Release in viewDidUnload and dealloc both?

I have been under the assumption for a while that viewDidUnload is always called when a controller is deallocated. Is this a correct assumption?

I've just been exploring some odd things, and set a breakpoint in my controller's viewDidUnload and it's dealloc. It appears that dealloc is called, but the viewDidUnload method is never called. I even added a self.view = nil to my dealloc and it still didn't seem to call it.

Does this mean that retained view objects I have been releasing in the viewDidUnload method also need to be released in my dealloc method to be sure they really go away?

I know there are many other questions on StackOverflow about viewDidUnload, but none specifically address this issue about duplication of release statements between the 2 methods.


A more concrete exmaple in a fresh project on the 3.1.2 SDK:

@implementation TestViewController

@synthesize label;

- (IBAction)push {
    TestViewController *controller = [[[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil] autorelease];
    [self.navigationController pushViewController:controller animated:YES];
}

- (void)viewDidUnload {
    self.label = nil;
    NSLog(@"viewDidUnload was called");
}

- (void)dealloc {
    [super dealloc];
    NSLog(@"label retain count: %i", [label retainCount]);
}

@end

My app delegate creates a simple navigation controller with one of these as it's root controller. When I tap the button linked to push 3 times, and then hit the back button three times, the following output is generated.

ViewDidUnloadTest[2887:207] label retain count: 2
ViewDidUnloadTest[2887:207] label retain count: 2
ViewDidUnloadTest[2887:207] label retain count: 2

Which is 2 higher that I would think it would be. Retained once by the view and once by the controller. But after the dealloc I would have expected the view to be gone releasing my label, and the controller to be gone calling viewDidUnload and releasing it. Although there may be an autorelease in there throwing off the count at this point.

But at least it's clear that viewDidUnload is not getting called at all, which contrary to this answer here: Are viewDidUnload and dealloc always called when tearing down a UIViewController?

Perhaps I should simply call [self viewDidUnload] in all my dealloc methods on controllers? Worse than can happen is that I set a property to nil twice, right?

like image 206
Alex Wayne Avatar asked Mar 01 '10 00:03

Alex Wayne


1 Answers

Unless you need to break a retain cycle, you should generally only be releasing objects in your dealloc method. viewDidUnload is an exception; it is invoked in low memory situations and should be used to release anything that you can.

If you do need to release them anywhere else, then always set the reference to nil after the release. That'll protect your app from blowing up later (likely in dealloc).

Note that the documentation quite explicitly calls out that the view property will already be nil when viewDidUnload is called.

like image 196
bbum Avatar answered Sep 28 '22 05:09

bbum