views:

502

answers:

4
+1  Q: 

Autorelease scope

Hi,

I was wondering how the autorelese works on the iPhone. I though that once you send an autorelease to an object it is guaranteed to be retained in till the end of the scope of the block the autorelease was sent. Is that correct?

I was initializing a view from a NIB in the applicationDidFinishLaunching like below:

    (void)applicationDidFinishLaunching:(UIApplication *)application {

    loginViewController = [[[LoginViewController alloc] initWithNibName:@"LoginView" bundle:nil] autorelease];

    [window addSubview: [loginViewController view]];
    [window makeKeyAndVisible];
}

and the view did not show at all, all there was on the screen was the UIWindow

Now once I removed the autorelease from the end of the controller initialization all went smooth from there on.

What is this about?

Cheers, K.

A: 

The autoreleasepool is cleaned at the end of the runloop. This means as long as you invoke methods and do stuff, it's still there.

I don't see the error in your code, but the Window is retained properly in your example.

Georg
A: 

Since you're adding your LoginViewController to the autorelease pool it's being released at the end of the run loop. When that happens it also releases its' view and removes it from being displayed.

Ashley Clark
The view should be retained by the window. (I don't have access to the documentation though.)
Georg
But when the view controller is deallocated, it removes the view it manages from its superview.
Don McCaughey
Precisely what Don said.
Ashley Clark
+5  A: 

When you call autorelease, you give ownership of the object to the current autorelease pool. The run loop creates a new autorelease pool before it dispatches an event (such as applicationDidFinishLaunching:) and destroys that pool when the event finishes.

When you give ownership of your LoginViewController to the autorelease pool, it gets released just after the applicationDidFinishLaunching: returns. When the view controller deallocates itself, it removes its view from the superview (your window in this case).

Your application delegate should keep ownership of the LoginViewController and release it in the app delegate's dealloc method (or when you're done with your login and have moved on to another view).

Don McCaughey
+3  A: 

To expand on Don's answer, it may be somewhat confusing to say "you give ownership of the object to the current autorelease pool." This might be misunderstood to mean the object is guaranteed to be destroyed when the autorelease pool is drained. This is not correct (though it will happen in this case). Sending -autorelease requests that the autorelease pool send a -release message when it is drained. If that -release message makes retainCount = 0, then the object will be destroyed.

So, in order to do what Don is recommending, you need to create a ivar to keep track of this view controller. His explanation of why the view vanishes is exactly right; but you don't want to just leak the view controller. You want to hold onto it, and release it when you're done with it.

@interface ... {
   LoginViewController *_loginViewController;
}

@property (readwrite, retain) LoginViewController *loginViewController;

@implementation ...
@synthesize loginViewController = _loginViewController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {

    self.loginViewController = [[[LoginViewController alloc] initWithNibName:@"LoginView" bundle:nil] autorelease];

    [window addSubview: [loginViewController view]];
    [window makeKeyAndVisible];
}

- (void)dealloc {
    [_loginViewController release]; _loginViewController = nil;
    [super dealloc];
}
Rob Napier