Memory leak when pushing a UIViewController - iphone

Each time I push a new viewcontroller, it adds about 3MB. TestVC is a brand new VC with one method for pushing a new version of the VC.
UIViewController *vc = [[TestVC alloc] initWithNibName:nibName bundle:nil];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
When I popviewController, it doesn't release any memory (watching activity monitor).
[self.navigationController popViewControllerAnimated: YES];
So, as I add navigate through the app (about 60 different pages), memory keeps building up. Does initWithNibName need something special. When I pop, do I need to release the nib somehow?

The most likely problem is a failure to release something in -[TestVC dealloc]. I would evaluate that method by inspection first. If you can't find the problem, use the Leaks instrument in Instruments to find what particular thing is being over-retained. If Leaks doesn't find it, then use the heapshot tool in Instruments to see what's being allocated. With something so large, it should be easy to find. There's a quick overview of using Heapshot on Use Your Loaf.

Related

When to release/autorelease VC's that will be pushed

I have come across previous problems which occur when I release a viewController after pushing it via the UINavigationController, so I now autorelease every viewController that will be pushed. But I often see code where the developer releases the viewController after pushing it.
My question is, when is the correct time to release/autorelease a UIViewController when pushed onto the stack?
Thanks
push
release
The navigation controller retains the view controller when you push it.
I would suggest any of your previous problems were nothing to do with the above process, but elsewhere.
ViewController *yourViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
[self.navigationController pushViewController:yourViewController animated:YES];
[yourViewController release];
Whether you autorelease the view controller before the push or release the view controller after the push makes little difference. The release after the push is a bit more efficient since it would cause the view controller to be released sooner (freeing up memory faster) but the autorelease will also release it soon, but a bit later.

Preventing bad access crash for popViewControllerAnimated in uinavigationcontroller setup

So, under low memory, my root view is unloaded. That's expected and accounted for. However, how do I deal with modal/pushed view controllers who need to be popped, since they reference the main navigationController? I have a custom Done button in a pushed view controller, which calls [self.navigationController popViewControllerAnimated:YES]. If the root view has been unloaded, this gives a bad access error. Is there a better way to do this?
My setup is
AppDelegate has a NavigationController
this NavigationController has a view controller MainViewController
//MainViewController.m
- (IBAction)showAnotherController:(id)sender
{
AnotherViewController * anotherViewController;
anotherViewController = [[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
[self.navigationController pushViewController:anotherViewController animated:YES];
[anotherViewController release];
}
//...Here I can simulate a memory warning to force unloading of MainViewController's view
//in AnotherViewController.m, called from a custom toolbar item
- (IBAction)done:(id)sender
{
[self.navigationController popViewControllerAnimated:YES]; // bad access here, looks like self.navigationController is no longer available. Am I doing this wrong?
}
The scenario you're describing does not cause bad access. However, if you don't handle the described scenario carefully you get bad access. Since you haven't showed me any code I can't tell you that this is the problem you're having, but it's a very common problem.
When you receive a memory warning and your view is unloaded, you probably release a bunch of stuff. In addition to releasing the variables you also have to set them to nil. If you don't, you're facing the risk of sending messages to released objects, which causes bad access.
Again, I can't know that this is your problem, but it's usually the problem.
EDIT: Since you seem to believe that self.navigationController doesn't exist (it probably does) I'm gonna tell you about something called NSZombie:
NSZombie will tell you what released object is being sent a message (aka EXC_BAD_ACCESS). This is a very useful tool when you get EXC_BAD_ACCESS, so learn how to use it.
To activate NSZombie do the following:
Get info of the executable.
Go to the arguments tab.
In the "Variables to be set in the environment:" section add:
Name: NSZombieEnabled
Value: YES
Then run your app as usual and when it crashes it should tell you which deallocated object received the message.

UIViewController class memory issue - presentModalViewController

I have some memory issue with my iPhone application and I have no clue what is happening.
So, I observed that the memory usage of the application is rising continuously when going from an UIViewController to another. I have used the "Mark Heap" tool from the "Allocations" instrument and it seams that the only objects that are not deallocated are my UIViewControllers.
To be more specific I have let take my two UIViewControllers. The first one is named PuzzleViewController and the second one is named Options. When the app starts, the PuzzleViewController appears. I mark a heap here, to set a baseline, and after this I press the "Options" button which will present the Options UIViewController. I go back to the first one and I mark a heap again. After repeating these steps over and over again (like 20 times or so :D) I observe that after every Heapshot I have about 22 objects remaining alive. Two of those objects are instances of my UIViewControllers.
I really don't have any clue what is happening.
Here is how I switch to the Options UIViewController:
- (IBAction) onOptionsButton: (id) sender
{
Options *viewController = [[Options alloc] init];
[self presentModalViewController:viewController animated:YES];
[viewController release];
}
And here is how I go back to the PuzzleViewController:
- (IBAction) onMainMenu:(id) sender
{
PuzzleViewController *modalView = [[PuzzleViewController alloc] init];
[self presentModalViewController:modalView animated:YES];
[modalView release];
}
My viewDidUnload functions are called properly, but no dealloc function is ever called.
Thank you,
Andrei
You should call dismissModalViewController, not presentModalViewController again, nor recreate your PuzzleViewController.
Dismissing a Modal View Controller

Releasing UIViewControllers and LLVM static analysis

When compiling my app with LLVM, just about the only errors I get are:
Potential leak of an object allocated on line xxx
This is in response to code creating and pushing a new UIViewController onto a UINavigationController:
FooViewController *vc = [[FooViewController alloc] initWithNibName:#"FooViewController" bundle:nil];
vc.title = #"FooFoo";
[self.navigationController pushViewController:vc animated:YES];
So I guess it's suggesting I put this after the last line:
[vc release];
But whenever I do that, it causes errors EXC_BAD_ACCESS. I don't see why I would release it anyway, since I want it to remain in memory, don't I? How would I get around this to make the LLVM compiler happy?
Your navigation controller will retain the view controller, so there's no need for you to do so. (i.e.: The [vc release]; line should be in there.)
As such, I'm guessing the problem with the EXC_BAD_ACCESS lies elsewhere, but it's hard to tell without some additional surrounding information.

release viewcontroller after presenting modally

I was watching CS193P Stanford course on Itunes, and in one of the lectures a demo was given and
There it was said you could present the viewcontroller modally and then release it. Roughly like this (I know this isn't perfect but I'm on my PC atm)
[self.view presentcontentmodally:myVC]
[myVC release];
However this seems to produce problems. If I put a NSLog(#"%d", [myVC retainCount]) between those two lines then it returns 2 implying it is ok to release. However when I dismiss the myVC the app crashes. Nothing in the NSlog and the debugger won't show where it stopped.
But I used malloc-history or something that some blog said would help. And found that it was the myVC.
So should I be releasing myVC?
(also when the modalVC has been dissmissed should the app's memory usuage go back to before the modalVC was presented?)
Yes, you should release your view controller after passing it to a modal navigation controller. Just make sure you are not passing in a previously retained view controller unless you plan to manage its release manually.
For example, follow the lifespan of _myViewController here:
MyViewController *_myViewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
UINavigationController *_modalNavigationController = [[UINavigationController alloc] initWithRootViewController:_myViewController];
[_myViewController release], _myViewController = nil;
[[self navigationController] presentModalViewController:_modalNavigationController animated:YES];
[_modalNavigationController release], _modalNavigationController = nil;
The modal navigation controller will increment the retain count of _myViewController, essentially taking ownership of it.
Once the modal navigation controller is dismissed and you are back to your original navigation controller, the modal navigation controller will receive a release message and in turn release its root view controller (_myViewController).
The retain count of this view controller will hit zero and the memory is then reclaimed.
I have just checked through a couple of my apps, and I am releasing my modal view controllers after each presentation, without problems. Which makes me think that you don't yet understand the Cocoa memory management model. Here's a sample:
TweetController *tweetController = [[TweetController alloc] init];
tweetController.content = content;
tweetController.delegate = self;
[self presentModalViewController:tweetController animated:YES];
[tweetController release];
Note that this controller was created with alloc/init, and wasn't previously released or autoreleased.
In addition, please don't rely on retain count checking; a retain could be from a previous autoreleased, which will go away very soon causing the sort of error you have been seeing.