+1  A: 

Your second code snipppet doesn't release the object you created.

self.rootViewController is a property that retains the object. So you're creating an object using alloc, and then the setter method for self.rootViewController will retain it also. You should release all objects that you allocated. Always

What happens is:

  1. You create an object of type RootViewController using alloc, so the retain count becomes 1
  2. The object is assigned to a property which also retains the object. So the retain count becomes 2

When self is deallocated later on, the retained RootViewController object will be released, so its retain count becomes 1 again.

Result: you have a memory leak.

Philippe Leybaert
You shouldn't release objects that you have allocated if the method name suggests it returns an object with +1 retain count.
dreamlax
sorry i forgot to mention i'm releasing self.rootViewController in the dealloc method
taber
It's all about ownership. Everything you allocate or retain through "alloc", "new" or "retain", you should release at one point (not necessarily in the same method). In other words, every "alloc", "new" or "retain" should be matched by a "release" in your code. Objects returned from other methods should not be released.
Philippe Leybaert
@taber: of course, and you should, but any local object that you created using "alloc" should be released. In your second example, you're effectively creating (and allocating) an anonymous local object, but you don't release it.
Philippe Leybaert
Thanks. Also here's a handy regexp for anyone who, like me, has made this mistake in their project(s): self\.(.*)\s?=\s?\[+(.*)\s+alloc Just throw that in Xcode's Project Find dialogue and set the dropdown to use "Regular Expression"
taber
+1  A: 

In the second code snippet there will be a memory leak because you omit the [self.rootViewController release] line.

In more detail:

  • When you call [[RootViewController alloc] init], the retain count of the created object will be 1.
  • Calling self.rootViewController = viewController will increase it to 2 because the self.rootViewController property is retaining.
  • Calling [viewController release] decreases the retain count to 1
  • So if you call self.rootViewController = nil later, then the retain count will be 0 (because the generated setter calls a release method), so the object will be deallocated.

In the second case, the retain count will be 1 when you call self.rootViewController = nil, so the object will never be released.

If you want a more compact solution, try this:

self.rootViewController = [[[RootViewController alloc] init] autorelease];
[window addSubview: [self.rootViewController view]];
gyim
sorry i forgot to mention i'm releasing self.rootViewController in the dealloc method
taber
+3  A: 

This line:

self.rootViewController = viewController

is identical to this line:

[self setRootViewController:viewController];

The typical setX call will release a previously retained value of X and assign a new retained value of X.

id old = X;
X = [new retain];
[old release];

But it can do anything else as well.

If you know there is not a current value to release (in init) and the setter function does nothing but retain the new value (synthesized), you can replace:

RootViewController *viewController = [[RootViewController alloc] init];
self.rootViewController = viewController; // self.rootViewController is a (nonatomic,retain) synthesized property
[viewController release];

With:

rootViewController = [[RootViewController alloc] init];

which does not use self. and so directly assigns a value instead of calling a setter method. Using the setter method is generally preferred.

To consolidate the lines as you want, you can also switch to this:

self.rootViewController = [[[RootViewController alloc] init] autorelease];

Which uses the setter method, releases the allocated instance, and fits on one line.

drawnonward
I would say to always prefer autorelease vs. init...release if you can. It's simpler and less error prone - everything is kept in one expression so you are unlikely to accidentally lose the 'release'.
Mike Weller
+1 to drawnonward for answering the question before fixing other things in the code.
pxl
A: 

Please read and understand the Cocoa Memory MAnagement Rules. You obtained the object with alloc, therefore you have ownership of it. By "you" I mean the executing code in the current scope. You need to either release or autorelease it to relinquish ownership. Assigning the object to something else (in this case a property) does not absolve you of your responsibility to relinquish ownership when done.

Your second example leaks. You can fix it thusly:

self.rootViewController = [[[RootViewController alloc] init] autorelease];

In Mac OS X, whether you use that or your first example is a just a matter of preferred style. With the iPhone, the first example is generally preferred because it doesn't involve adding an object to the autorelease pool. Having said that, since a view controller will probably need to stick around beyond the end of the current event, it makes little difference.

By the way, two answers have mentioned retain counts and they are both correct, but it is better to avoid thinking about retain counts at all and think only in terms of ownership. Retain counts are an implementation detail.

JeremyP
Thanks, I already read that. I guess the "understanding" part of it is the reason I'm asking this question. :) I also forgot to mention that this is for the iPhone - it's better to avoid autorelease when coding for the iPhone, correct? Again, I really just want to know the difference (if any) between the two methods of creating the new RootViewController object "behind the scenes." - creating a temporary viewController obj versus setting the result of alloc init to self.rootViewController directly.
taber
Also, actually it looks like using the second "shorter" version creates a retain count of 2... see my answer below.
taber
A: 

Thank you guys for your answers! I was looking for less "read the memory management guide" type of answers and more of a "dumbed down," "here's the background and difference between these two methods laid out for you" type of answer. I'm familiar with object ownership, retain counts, etc. but I didn't realize WHY using *self.*rootViewController was important, and WHY the second code snippet was leaking... and literally the "behind the scenes" difference between the two. So I came across this post which was I feel was the exact answer I was looking for... (I hope it's accurate!) :) but anyway I'm giving the ole check mark to Philippe because he answered first. I just didn't understand his answer until reading the following post...

http://www.iphonedevsdk.com/forum/iphone-sdk-tutorials/7295-getters-setters-properties-newbie.html

This part was key for me:


So what would happen if you wrote:

self.obj = [[SomeObject alloc] init];

In this case, you're holding onto an object with a retain count of two - the first count comes from the "alloc" and the second one is added by the setter.

To release this variable, you'd have to do something like this:

[obj release];
self.obj = newValue;

so that "release" gets called twice on the object. If you omit the extra "release", then when the pointer gets overwritten the object will still be floating around with a retain count of one, and thus doesn't get deallocated. Instant memory leak.


Thanks again!

taber
People say "read the memory management guide" for good reason. It's the best account "dumbed down" or otherwise of how to do memory management in reference counted Cocoa.
JeremyP
And you are still thinking too much in terms of retain counts. Forget about them, think only of whether you own the object or not.
JeremyP
I read it! I know it's all about object ownership, but in this case the extra retain count was creating a leak. So I'd rather not just forget about them. Thanks for the input.
taber