Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does UIView's addSubview really retain the view?

I ran into a situation that seems to suggest otherwise. In the following code snippet, if I remove the line: self.navigationController = nav, the root controller's view won't show up, suggesting to me that addSubview might not actually retain the view as otherwise suggested. Any idea?

- (void)applicationDidFinishLaunching:(UIApplication *)application {   
   self.testViewController = [[TestViewController alloc] initWithNibName:@"TestView" bundle:  [NSBundle mainBundle]];

   UINavigationController *nav = [[UINavigationController alloc]  initWithRootViewController:self.testViewController];

   self.navigationController = nav;  //<-- if this line is removed, test view won't show up

   [window addSubview:nav.view];

   [nav release];
}
like image 499
Boon Avatar asked Jun 02 '09 03:06

Boon


1 Answers

This line:

[window addSubview:nav.view];

does NOT add a view to the screen immediately. It is displayed by the OS in some future run loop on a possibly different thread. The actual implementation we can't be sure of.

This is why Apple defines delegate methods like viewDidAppear/viewWillAppear, otherwise we would not need them as we would know precisely when these events occur.

Moreover, adding a subview as you said, does indeed retains the view. It does NOT however retain the view controller or the navigation controller. Since the navigation controller WILL retain any added view controllers, we do not have to back them with an ivar.

But, your reference to the navigation controller must persist beyond the scope of the method. or depending on your code it could be dealloc-ed or have its reference lost.

So you must keep a reference to the navigation controller with an ivar and set it like so:

self.navigationController = nav; 

So even though nav.view contains a pointer to testViewController.view, the application has no reference the navigation controller and, by extension, the view. The result is a blank screen.


To make this more obvious that it isn't a retain/release problem, you are actually leaking in the following method:

self.testViewController = [[TestViewController alloc] initWithNibName:@"TestView" bundle: [NSBundle mainBundle]];

You need to autorelease to balance out your retain/releases by:

self.testViewController = [[[TestViewController alloc] initWithNibName:@"TestView" bundle: [NSBundle mainBundle]] autorelease];

So, that means your view has never, ever been deallocated any time you have ran this code. Which further assures us that your issue is indeed a lost reference.

like image 117
Corey Floyd Avatar answered Oct 06 '22 01:10

Corey Floyd