2

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)?

Community
  • 1
  • 1

3 Answers3

5

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.

hundreth
  • 841
  • 4
  • 8
  • that is completely right! the idea is that your view controller should be able to go through many loadView(+viewDidLoad)/viewDidUnload-Cycles without leaking memory or accessing zombies. best examples are VCs in a Tab Bar Controller - they are allocated one and then go through loadView/viewDidUnload when you click through the tabs – Martin Ullrich Jun 22 '11 at 16:35
  • Should not call [super loadView] in the custom loadView method. Code like below: self.view = [[[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame]autorelease]; – Wubao Li Jun 13 '12 at 11:39
  • Want to explain why Wubao? I've never had a problem calling [super loadView]. – hundreth Jun 13 '12 at 14:26
2

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.

Peter DeWeese
  • 18,141
  • 8
  • 79
  • 101
  • Is it smart to call the same "release method" in **viewDidUnload** and *dealloc**? Typically, we set the @property as "(nonatomic, retain)" and as such the setter that is created for you releases the current object and then retains the argument. That is, `self.myProperty = nil;` in **viewDidUnload** does something like `[myProperty release]; myProperty = [nil retain];`... Then, in **dealloc**, all we do is `[myProperty release]`. – Seth Lowenstein Jun 22 '11 at 16:14
  • It is perfectly safe to use my pattern, and there is no need to do it differently in dealloc than in viewDidUnload. For a retained property self.property = nil is equivalent to [property release], property = nil; And although it shouldn't matter in dealloc to set it to nil, it is still a good idea in case you accidentally try to access it later. You should reduce redundancy and the number of places in which you have to define the same functionality. – Peter DeWeese Jun 22 '11 at 17:01
0

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.

csano
  • 13,266
  • 2
  • 28
  • 45
  • I'm releasing my subviews in **dealloc**. Do I *also* have to release my subviews and set them to nil in **viewDidUnload**? – Seth Lowenstein Jun 22 '11 at 16:09
  • @Seth Lowenstein: It depends. From the documentation: "You should do this only for objects that you can easily recreate later, either in your viewDidLoad method or from other parts of your application. You should not use this method to release user data or any other information that cannot be easily recreated" – csano Jun 22 '11 at 16:21