views:

877

answers:

3

I see a lot of code, particularly in Apple example code, that resembles the following:

   EditingViewController *controller = [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];
    self.editingViewController = controller;
    [controller release];

Is there any reason in particular that the approach above proves beneficial over:

self.editingViewController = [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];

Trying to understand if there is a strategy for the above.

Thanks!

+4  A: 

You could write:

self.editingViewController = [[[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil] autorelease];

And I often do in non-speed critical areas. The problem is that the property is most likely a "retain" property, which means that if you don't release it, the object will be leaked.

It should be noted that autorelease is more expensive than release, but I also prefer brevity of code for readability over pure speed.

NilObject
even if it were a copy property, you'd leak.
Graham Lee
I think you missed the call to autorelease at the end.
Don McCaughey
A: 

This is going to leave you with a memory leak, as the object isn't released.

But honestly, even Apple doesn't get it always right in their documentation, you shouldn't use release here.

Corrected this should be:

// use EditingViewController instead of id
id controller = [[[EditingViewController alloc]
                   initWithNibName:@"EditingView" bundle:nil]
                   autorelease];
self.editingViewController = controller;

Why should it be autoreleased? In good Objective-C code, there is the same number of retain as release.

Georg
The Apple code that Coocoo4Cocoa quoted includes a release message. Therefore, it is balanced. The only difference is that the release happens immediately after the property set message, not “later” when the pool gets drained.
Peter Hosey
There's no retain. Of course alloc retains it, but good coding style is to have balanced retain and release counts. It's easier to detect errors.
Georg
Good coding style is to release what you have allocked, copied, or retained. There's no reason it has to be specifically a retain message, and there's no reason why it has to be autorelease instead of release.
Peter Hosey
autorelease is not good practice for iPhone because it increases memory footprint. Better to control the memory properly with release.
Roger Nolan
gs - in good Objective-C code, your memory management should work. Refcounting is a Cocoa feature in non-GC environments; and it is there where there should be balanced refcounts. Both your example and the Apple example are balanced, though explicit release is preferable to autorelease.
Graham Lee
Both are correct, but in my opinion this is a case where autorelease is to be preferred over the normal release.
Georg
+7  A: 

On first glance, it would seem that your example would work, but in fact it creates a memory leak.

By convention in Cocoa and Cocoa-touch, any object created using [[SomeClass alloc] initX] or [SomeClass newX] is created with a retain count of one. You are responsible for calling [someClassInstance release] when you're done with your new instance, typically in your dealloc method.

Where this gets tricky is when you assign your new object to a property instead of an instance variable. Most properties are defined as retain or copy, which means they either increment the object's retain count when set, or make a copy of the object, leaving the original untouched.

In your example, you probably have this in your .h file:

@property (retain) EditingViewController *editingViewController;

So in your first example:

EditingViewController *controller = 
    [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];
// (1) new object created with retain count of 1

self.editingViewController = controller;
// (2) equivalent to [self setEditingViewController: controller];
// increments retain count to 2

[controller release];
// (3) decrements retain count to 1

But for your second example:

// (2) property setter increments retain count to 2
self.editingViewController = 

    // (1) new object created with retain count of 1
    [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];

// oops! retain count is now 2

By calling the autorelease method on your new object before passing it to the setter, you ask the autorelease pool to take ownership of the object and release it some time in the future, so for a while the object has two owners to match its retain count and everything is hunky dory.

// (3) property setter increments retain count to 2
self.editingViewController = 

    // (1) new object created with retain count of 1
    [[[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil]

        // (2) give ownership to autorelease pool 
        autorelease];

// okay, retain count is 2 with 2 owners (self and autorelease pool)

Another option would be to assign the new object directly to the instance variable instead of the property setter. Assuming your code named the underlying instance variable editingViewController:

// (2) assignment to an instance variable doesn't change retain count
editingViewController = 

    // (1) new object created with retain count of 1
    [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];

// yay! retain count is 1

That's a subtle but critical difference in the code. In these examples, self.editingViewController = x is syntactic sugar for [self setEditingViewController: x] but editingViewController is a plain old instance variable without any retain or copy code generated by the compiler.

See also http://stackoverflow.com/questions/612986/why-does-this-create-a-memory-leak-iphone

Don McCaughey