views:

359

answers:

1

I'm having a hard time undestand a couple of the methods in UIViewController, but first I'll say what I think they are meant for (ignoring interface builder because I'm not using it):

-init: initialize non view-related stuff that won't need to be released in low memory situations (i.e. not objects or objects that can't be recreated easily).
-loadView: create the view set the [self view] property.
-viewDidLoad: Create all the other view elements
-viewDidUnload: Release objects created in -viewDidLoad.
didReceiveMemoryWarning: Low-memory situation, release unnecessary things such as cached data, if this view doesn't have a superview then the [super didReceiveMemoryWarning] will go on to release (unload) the view and call -viewDidUnload.
-dealloc: release everything
-viewWillAppear:, -viewDidAppear:, -viewWillDisappear:, -viewDidDisappear: self-explanatory, not necessary unless you want to respond (do something) to those events.

I'm not sure about a couple of things. First, the Apple docs say that when -viewDidUnload is called, the view has already been released and set to nil.

  1. Will -loadView get called again to recreate the view later on?
  2. There's a few things I created in -viewDidLoad that I didn't make a ivar/property for because there is no need and it will be retained by the view (because they are subviews of it). So when the view is released, it will release those too, right? When the view is released, will it release all its subviews? Because all the objects I created in -viewDidLoad are subviews of [self view]. So if they already get released why release them again in -viewDidUnload? I can understand data that is necessary when the view is visible being loaded and unloaded in these methods, but like I asked, why release the subviews if they already get released?

EDIT: After reading other questions, I think I might have got it (my 2nd question). In the situation where I just use a local variable, alloc it, make it a subview and release, it will have a retain count of 1 (from adding it as a subview), so when the view is released it is too. Now for the view elements with ivars pointing to them, I wasn't using properties because no outside class would need to access them. But now I think that that's wrong, because in this situation:

// MyViewController.h
@interface MyViewController : UIViewController {
    UILabel *myLabel;
}

// MyViewController.m
. . .
- (void)viewDidLoad {
    myLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 10)];
    [myLabel setText:@"Foobar"];
    [[self view] addSubview:myLabel];
}

- (void)viewDidUnload [
    // equivalent of [self setMyLabel:nil]; without properties
    [myLabel release];
    myLabel = nil;
}

In that situation, the label will be sent the -release message after it was deallocated because the ivar didn't retain it (because it wasn't a property). But with a property the retain count would be two: the view retaining it and the property. So then in -viewDidUnload it will get deallocated. So its best to just always use properties for these things, am I right? Or not?

+2  A: 

Will -loadView get called again to recreate the view later on?

Yes, as soon as somebody accesses the view property.

When the view is released, will it release all its subviews?

Yes.

As for the labels and such stuff you don’t need later, the usual approach is to simply release them after you attach them to the view:

UILabel *foo = [[UILabel alloc] init…];
[self.view addSubview:foo];
[foo release];

In this case the label will be deallocated when the view gets deallocated.


Memory management in your example is fine. When you alloc the label, its retainCount hops to 1, the view retains it (retainCount = 2), then the view gets deallocated and releases the label (rc = 1) and then you finally release the label yourself (rc = 0, dealloc).

To make things even more clear – the variable myLabel does not retain the label explicitly, but you still own it because you allocated it. That’s one of the basic rules of Cocoa memory management: alloc +1, retain +1, release -1, autorelease -1 later.

Example:

@property(retain) UILabel *foo;
self.foo = [[UILabel alloc] init…];

This would be a leak, because the label gets a +1 during alloc and another +1 in the setter generated for the foo property. Read the Cocoa Memory Management Guide or Scott Stevenson’s Objective-C tutorial. The memory management in Cocoa is pretty simple and after a bit of thinking you should be perfectly comfortable in all situations.

zoul
Thanks, I understand that now. But was I right about using properties, the last part of my post I edited?
Mk12
What I'm asking is just to confirm this: Besides unloading data that you will recreate in `-viewDidLoad`, `-viewDidUnload` is for releasing properties (`[self setProperty:nil]`) that are still retaining subviews of `[self view]`, that `[self view]` has already released, so they can be deallocated. Am I right?
Mk12
But I thought that the example there was code that didn't work? Because the member variable myLabel never retains the UILabel (only the view does), but it still releases it in `-viewDidUnload`. Or were you talking about what I was describing after? What I'm trying to decide is should I just always use properties for things like this (where I need a member variable)?
Mk12
Thanks, I get it now. I had forgotten that alloc increases the retain count. So if I don't need to expose the member variables, I don't need to use properties if I don't want to.
Mk12
Yes. You’re welcome, happy hacking!
zoul