4

Why do I need to create a pointer just to allocate memory and then release it immediately?

In other words, can't I just do this:

self.viewController = [[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController" bundle:[NSBundle mainBundle]];

instead of this:

HelloWorldViewController *newViewController = [[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController" bundle:[NSBundle mainBundle]];
self.viewController = newViewController;
[newViewController release];

[EDIT]

To provide wider context on my question: (within @implementation of @interface HelloWorldAppDelegate : NSObject <UIApplicationDelegate>)

@synthesize window=_window;
@synthesize viewController=_viewController;

...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    HelloWorldViewController *newViewController = [[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController" bundle:[NSBundle mainBundle]];
    self.viewController = newViewController;
    [newViewController release];

    self.window.rootViewController = self.viewController;

    [self.window makeKeyAndVisible];
    return YES;
}

...

- (void)dealloc
{
    [_window release];
    [_viewController release];
    [super dealloc];
}

So, within the didFinish... method, can I use the short version I supplied way above, or would it leak?

[SECOND EDIT]

Seems I just can't give enough info. I'm always hesitant to post a huge pile of code. I've got this in HelloWorldAppDelegate.h:

@property (nonatomic, retain) IBOutlet HelloWorldViewController *viewController;

So, correct me if I'm wrong. Given the declaration of viewController in the header file, if I use the shortcut method (in the first code snippet above), the program will leak. The object counter is incremented once by the alloc, and then a second time by the retain, then decremented once by the release, producing a net of +1 on the pointer reference counter.

Matt
  • 685
  • 1
  • 8
  • 16
  • Updated my answer in response to your update. The TL;DR version is: No, you still need to release it. – jscs May 05 '11 at 23:53

2 Answers2

3

You do have to release the object that you allocated, or you will end up with a memory leak. The assignment to self.viewController (presumably) retains the newly-alloc'd HelloWorldViewController, so you have two "claims" on the object -- one from your call to alloc and one from the retain, but you're not actually going to use it any more under the name newViewController, so you relinquish that particular claim by calling release.

The "long" form, using the temp variable, is in fact the correct way to do this. Sending release to the result of the property access: [self.viewController release]; right after it's set is quite likely to work, but is incorrect (and will generate a compiler warning for recent LLVM versions).

It's also possible to do this:

self.viewController = [[[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController" 
                                                                  bundle:[NSBundle mainBundle]]
                          autorelease];

which says "I've created this thing to use it briefly, but I won't need it outside this immediate call stack, so go ahead and release it for me later."

If viewController isn't a retaining property, then all this is moot, and you should not be sending release to the new view controller, because it will then be deallocated before you can use it.

UPDATE: Your expanded question doesn't change anything*. If you don't send release before newViewController goes out of scope, you will end up with a leak.** The way this works is, any object (A, B, C) that needs to use object X, and therefore cares about keeping it around, sends retain to X. When you alloc an object, it's assumed that you need to use it. When any of A, B, or C no longer need X, it sends release to X, thereby saying "X can be deallocated and it won't affect me". You need to balance the number of claims you make (by using retain, alloc, copy/mutableCopy, or new) on an object with the number of relinquishments you make (by sending release or autorelease) or you will have either a leak or an accidental deallocation on your hands.

I'm going to give you a link to the docs now, but don't be annoyed, it's just one page that you need to read and internalize: The Fundamental Rule of Cocoa Memory Management.


*Actually, you left out the only part that could've changed the answer, namely your

@property () HelloWorldViewController * viewController;

declaration. If it says "retain" inside those parentheses, then when this property is set, your app delegate is sending retain to the passed object. If it says "assign", or the parentheses aren't there, then, like I said, you should not send release to that object.

**Note for any pedants looking on: you could of course send release twice to the viewController at some point, but that's worse than a leak.

Community
  • 1
  • 1
jscs
  • 63,694
  • 13
  • 151
  • 195
  • Edited my post (again). Sorry if I'm laboring the point, but I want to make sure I've got my head wrapped around this. – Matt May 06 '11 at 16:42
  • @Matt: No problem. Yes, you've got it. Just be sure to only think of reference counts in "net" terms as you did here and not as an absolute number; the frameworks can and do retain things behind the scenes, without your knowledge. – jscs May 06 '11 at 16:46
2

Yes you can do this. Except you have to release self.viewController so that the retain count is 1 by the end of the snippet.

Let's count. Upon allocation, the release count is 1. Assiging it to self.viewController (assuming it's a property with retain behavior) increases it to two. Releasing it at the end of the second snippet makes it 1 again. The idea is that you'll release it completely in the dealloc of the current class, whatever that is.

The only wrinkle is that releasing an object variable assumes that you're done with it, and here you have to go, releasing self.viewController but using it later. Kinda smelly.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • You can send `autorelease` to the object when you create it instead. That looks cleaner and accomplishes the same thing. – Kyle May 05 '11 at 22:36
  • One thing to be wary of here is talking about retain counts as if they are absolute. You should only worry about the number of times that you yourself have caused the retain count to change, not its numerical value. – jscs May 05 '11 at 22:52
  • So, I suppose I need to provide wider context. – Matt May 05 '11 at 23:22