Reputation: 5388
I'm getting reports of memory leaks in my app, but I can't track down exactly what is happening. I have a function which takes out an old view and swaps in a new view. I'm not using NavControllers or any @properties; I'm managing my top-level window directly.
-(void)swapInView:(UIViewController*)newViewController
{
[currentViewer.view removeFromSuperview];
printf("Old viewController (%p) has count of %d; now releasing\n",
currentViewer, [currentViewer retainCount]);
[currentViewer release];
currentViewer = 0;
currentViewer = newViewController;
[currentViewer retain];
[mainWindow addSubview:currentViewer.view];
[mainWindow bringSubviewToFront:currentViewer.view];
}
When run the code, I show that the current view controller is being deallocated, and then my dealloc method for that view controller is getting called. But, Instruments/leaks still reports it as a leak. For instance, I get this print out:
Old viewController (0x119f80) has count of 1; now releasing
Deallocating WelcomeScreenViewController
I can verify from the address, that this is the same object being allocated previously.
My external code looks something like this:
MyViewController *theViewController = [[MyViewController alloc]
initWithNibName:nil
bundle:nil];
[GameMaster swapInNewView:theViewController];
[theViewController release];
Does anybody have any suggestions of how to track down what is going on? I'm using the 3.1.2 SDK, but I was also seeing this on earlier SDK's.
Upvotes: 2
Views: 310
Reputation: 119144
Huh. This was a fun one. I wrote a quick test to make sure neither of us was insane.
In the end, it all comes down to the calling code:
[[MyViewController alloc] initWithNibName:nil bundle:nil];
When you initialize a view controller, its view
object has not yet been defined, and will not be defined until requested.
Since you specify nil
for the nib name, you must override loadView
in your UIViewController
subclass in order to set the view object properly. See Apple's documentation for details.
The default implementation of loadView
apparently does some behind-the-scenes magic, and that magic can result in a memory leak.
So: when you make this call:
[mainWindow addSubview:currentViewer.view];
You are actually making two calls:
One: currentViewer.view
, which results in a call to [currentViewer loadView]
, and
Two: [mainWindow addSubview:...]
, which attempts to add the newly loaded view.
Leaks identifies this line because of the first call, and not the second one.
To verify, simply modify the loadView
method in your custom UIViewController
subclasses:
- (void)loadView
{
[self setView:[[UIView new] autorelease]];
}
This prevents the call to the default loadView
and now there are no more leaks.
Obviously, once you develop this application further, you will either have to put something more meaningful in loadView
, or use nibs.
Upvotes: 3
Reputation: 2071
Note the documentation for the removeFromSuperview method:
"Unlinks the receiver from its superview and its window, removes it from the responder chain, and invalidates its cursor rectangles. The receiver is also released"
I'm not sure if this is your problem or not, but doing:
[exampleViewController.view removeFromSuperview];
[exampleViewController release];
In my application causes a delayed crash due to over-releasing an object.
Upvotes: 0