views:

8163

answers:

6

What is the difference between the following 2 ways to allocate and init an object?

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

and

self.aController= [[AController alloc] init];

Most of the apple example use the first method. Why would you allocate, init and object and then release immediately?

A: 

I'm just a C++ programmer, but I'd bet the first may use heap space whereas the second should only use stack...

Nowhere man
You would lose the bet. Objective-C objects are always allocated on the heap.
benzado
Good to know... I should take a look at Objective-C some day, just for the sake of curiosity.
Nowhere man
+22  A: 

Every object has a reference count. When it goes to 0, the object is deallocated.

Assuming the property was declared as @property (retain):

Your first example, line by line:

  1. The object is created by alloc, it has a reference count of 1.
  2. The object is handed over to self's setAController: method, which sends it a retain message (because the method doesn't know where the object is coming from), incrementing its reference count to 2.
  3. The calling code no longer needs the object itself, so it calls release, decrementing the reference count to 1.

Your second example basically does steps 1 and 2 but not 3, so at the end the object's reference count is 2.

The rule is that if you create an object, you are responsible for releasing it when you're done with it. In your example, the code is done with tempAController after it sets the property. It is the setter method's responsibility to call retain if it needs that object to stick around.

It's important to remember that self.property = foo; in Objective-C is really just shorthand for [self setProperty:foo]; and that the setProperty: method is going to be retaining or copying objects as needed.

If the property was declared @property (copy), then the object would have been copied instead of retained. In the first example, the original object would be released right away; in the second example, the original object's reference count would be 1 even though it should be 0. So you would still want to write your code the same way.

If the property was declared @property (assign), then self isn't claiming ownership of the object, and somebody else needs to retain it. In this case, the first example would be incorrect. These sorts of properties are rare, usually only used for object delegates.

benzado
This is only the case if 'aController' is declared with the @property(retain) though, right?
That is correct.
Hans Sjunnesson
It’s also the correct pattern if the property is declared (copying). The second pattern is correct for a property declared (assign) (or with garbage collection enabled).
Ahruman
This is the "accepted" answer, but I strongly advise you to read mmalc's answer below, too. It shows how to do this in a more practical manner (with a tiny, tiny, tiny performance effect).
Adam
+1  A: 

Note also that your desire to cut the code down to one line is why many people use Autorelease:

self.aController = [[[AController alloc] init] autorelease];

Though in theory on the iPhone autorelease is somehow more expensive (never heard a clear explanation why) and thus you may want to explicitly release right after you assign the object elsewhere.

Kendall Helmstetter Gelner
I dont think it is more expensive than autorelease in Cocoa. Just that autorelease is more expensive than release. So if you can release the object instead of autoreleasing you should do so.
schwa
autorelease is more expensive because it has to find a thread-local data structure and add to it (the autorelease pool), whereas release just decrements an integer (the reference count).
benzado
@benzado: Yes, the question was why is autorelease more expensive **on the iPhone**, not why it is more expensive than release.
Sergio Acosta
I never autorelease unless I have to..
Mk12
+1  A: 

One other thing to note is that your example depends on the @property definition of aController also.

If it were defined as @property (readwrite, retain) id aController; then your example works, while if it is defined as @property (readwrite, assign) id aController; then the extra call to release would cause your object to be deallocated.

Ashley Clark
There's no point of specifying readwrite, since it is the default.
Mk12
+11  A: 

As others have noted, the two code snippets you show are not equivalent (for memory management reasons). As to why the former is chosen over the latter:

The correct formulation of the latter would be

self.aController= [[[AController alloc] init] autorelease];

Compared with the former, this adds additional overhead through use of the autorelease pool, and in some circumstances will lead to the lifetime of the object being unnecessarily extended (until the autorelease pool is released) which will increase your application's memory footprint.

The other "possible" implementation (depending on where the example is from) is simply:

aController = [[AController alloc] init];

However, setting an instance variable directly is strongly discouraged anywhere other than in an init or dealloc method. Elsewhere you should always use accessor methods.

This brings us then to the implementation shown in sample code:

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

This follows best practice since:

  • It avoids autorelease;
  • It makes the memory management semantics immediately clear;
  • It uses an accessor method to set the instance variable.
mmalc
mmalc's right. But ... in practice, 3 lines of code to assign to 1 variable is simply insane. Most teams I've seen use the autorelease "do it all in a single line of code" approach - the overhead is VANISHINGLY small. If you ever hit a situation on iPhone where it makes a significant performance difference, you should probably be rewriting that code in C anyway - you're doing too much allocation. Few teams will stick to the "official" convention (rightly so IMHO - real-world programs should be clear, but not to the point of verbal diarrhoea).
Adam
A: 

You could also do

@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];

with a retaining property, and it would function the same way, but its better to use the other way (for retaining properties) because it's less confusing, that code makes it look like you assign aController and then it gets deleted from memory, when actually it doesn't because setAController retains it.

Mk12
It'd be even worse if this were a copying property. You'd be releasing the copy, leaving a dead object in the instance variable, and leaking the object you allocked and inited.
Peter Hosey
But it does work if it's retaining. Not that you should do that.
Mk12