Please help: UINavigationController and view controllers memory management - iphone

I have a strange problem with a method is called each time a button is pressed:
- (void)launcherView:(TTLauncherView*)lnchr didSelectItem:(TTLauncherItem*)itm {
MyObject* obj = ...
MyViewController* detailView = [[MyViewController alloc] init]; // line A
[self.navigationController pushViewController:detailView animated:YES];
[detailView setObject:obj];
detailView = nil; // should I also release it? -- line B
}
The problem is that I apologize I have to release detailView (memory tool shows me I have a memory leak is it is not done), also because navigationController should retain my detailView, but both if I try to add autorelease in line "A" or in line "B", or simply a release for detailView in line "B" (of course before assigning it nil), the program crashes with an EXC_BAD_ACCESS 'cause release message sent to deallocated instance [CALayer]...
Any idea?
Thanks a lot

try it this way
- (void)launcherView:(TTLauncherView*)lnchr didSelectItem:(TTLauncherItem*)itm {
MyObject* obj = ...
MyViewController* detailView = [[MyViewController alloc] init];
[detailView setObject:obj];
[self.navigationController pushViewController:detailView animated:YES];
[detailView release];
detailView = nil; // now this will be optional
}

Does this work without crashing?
- (void)launcherView:(TTLauncherView*)lnchr didSelectItem:(TTLauncherItem*)itm {
MyObject* obj = ...
MyViewController* detailView = [[MyViewController alloc] init];
[self.navigationController pushViewController:detailView animated:YES];
//[detailView setObject:obj]; // <- What's this for?
[detailView release]
}

try "initwithnibname"
unrelated but if you chase memory leaks don't forget to release MyObject

When you set detailView = nil; without releasing it, you only nil the pointer to the memory. The block of memory is still allocated until you release it.
You must use [detailView release] before detailView = nil or else you will have no way to reference that block of memory again (memory leak).

Related

App crashes when view controller popped from navigation controller

I am pushing an object on navigation controller but when I return the control from the that view controller it crashes the app.
[self.navigationController pushViewController:chequeDetails animated:YES];
[chequeDetails release];
but when I write the same code with
[self.navigationController pushViewController:chequeDetails animated:YES];
chequeDetails=nil;
[chequeDetails release];
The app does not crash but a slight lag is observed... when i pop back from the check details controller?
If your seconds exaple code, you are not release the chequeDetails since calling release on a nil object does not nothing:
[self.navigationController pushViewController:chequeDetails animated:YES];
chequeDetails=nil;
// calling the release on nill will do nothing
[chequeDetails release];
Normally you can do it this ways:
[self.navigationController pushViewController:chequeDetails animated:YES];
[chequeDetails release], chequeDetails = nil;
But only release the chequeDetails if you did a alloc, init like:
ChequeDetails *chequeDetails = [[ChequeDetails alloc] initWithNibName:#"ChequeDetails" bundle:nil];
So the full code should be something like:
ChequeDetails *chequeDetails = [[ChequeDetails alloc] initWithNibName:#"ChequeDetails" bundle:nil];
[self.navigationController pushViewController:chequeDetails animated:YES];
[chequeDetails release], chequeDetails = nil;
I dont Know Exat... but i think you need to create a object of your delegate and you need to write appDelegate.navigationController rather then self.navigationController...
Note: appDelegate is a object of Delegate.

Bad memory leak when creating a view - even though a 'release' is present?

Part of my code presents a UITableViewController in the following way:
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"Settings" bundle:nil];
flipside = [[UINavigationController alloc] initWithRootViewController:controller];
controller.delegate = self;
flipside.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:flipside animated:YES];
[flipside release];
[controller release];
Using the leaks tools, no memory leaks are picked up on. However, whenever I bring up the settings menu (as shown in the code above), more memory appears to be allocated and never released - almost 100 kB every time.
Weirdly, the inclusion of the two release statements at the end seems to have no effect on the memory allocation..? Is there something I am misunderstanding about memory allocation in objective-c, or is something weird going on?
Any ideas are much appreciated - thanks!
If flipside is a retained property then the navigation controller is leaking. the problem is that you are bypassing the accessor method and releasing flipside directly. This is just messy code. A better way to do it would be to make an accessor method for flipside that will only alloc a new one if you haven't already created one. It's called lazy loading. To do this, just leave the #synthesize for flipside (but you shouldn't set it from outside the accessor method), in your header file change the property to, and add this method to the implementation:
- (UINavigationController *)flipside {
if (flipside != nil) {
return flipside;
}
FlipsideViewController *controller = [[[[FlipsideViewController alloc] initWithNibName:#"Settings" bundle:nil];
controller.delegate = self;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
[controller release];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
// This implies a retain if your flipside property is set to retain
self.flipside = navController;
[navController release];
}
make sure to put self.flipside = nil in the viewDidUnload method of the view controller the code you included came from (I assume it's a presentSettings action).
what your presentSetting action should now look like is this:
- (IBAction)presentSettings {
// make sure you use the accessor self.flipside instead on accessing the variable directly
[self presentModalViewController:self.flipside animated:YES];
}

UIViewController either leaks memory or crashes app if autoreleased

I have this code in my app and it says memory leak at 'gvc'.
GameViewController* gvc = [[GameViewController alloc] init];
[self.navigationController pushViewController:gvc animated:YES];
If i modify this code to autorelease view controller, it crashes my app after a while giving error 'Missed Method'
GameViewController* gvc = [[[GameViewController alloc] init] autorelease];
[self.navigationController pushViewController:gvc animated:YES];
Is there something wrong with autorelease? How to resolve this memory leak?
Thanks in advance.
You can safely do this:
GameViewController* gvc = [[[GameViewController alloc] init] autorelease];
[self.navigationController pushViewController:gvc animated:YES];
or this:
GameViewController* gvc = [[GameViewController alloc] init];
[self.navigationController pushViewController:gvc animated:YES];
[gvc release];
They are functionally equivalent and don't cause memory leaks or crashes. Look at your code after [self.navigationController pushViewController:gvc animated:YES]; to see if you over-release gvc.
Just release it when you're all done. If you need it all the time, then put GameViewController *gvc; in the header and put [gvc release]; in the dealloc method.
The obvious solution is simply to release the view controller once you've pushed it onto the nav controller.
i.e.:
GameViewController* gvc = [[GameViewController alloc] init];
[self.navigationController pushViewController:gvc animated:YES];
[gvc release];
That said, I'd be surprised if the autorelease was actually causing a memory leak at all.
It may be everything. I mean, your first code is obviously leaking, and the second code snippet is ok at first glance, but we don't know what you implement inside that class. Imagine in GameViewController, you have a string property userName, and in its dealloc, you do something like:
- (void)dealloc
{
[userName release];
[userName release];
[super dealloc];
}
Then of course it crashes when you release the controller. You should use gdb backtrace (type "bt" when it crashes) to see exactly where it crashes, or better yet, try to enable NSZombie and use instruments to find out.
Btw as a rule of thumbs in iPhone/iPad programming (where resources are scarce), try to avoid autorelease whenever you can.

Need help fixing iPhone memory leaks!

I encountered some strange memory leaks executing following code on iPhone device:
#implementation TestViewController
#synthesize myButton;
- (IBAction)buttonPressed {
ABPeoplePickerNavigationController* selectContactViewController = nil;
selectContactViewController = [[ABPeoplePickerNavigationController alloc] init];
selectContactViewController.peoplePickerDelegate = self;
[self presentModalViewController:selectContactViewController animated:YES];
[selectContactViewController release];
}
Releasing the picker simple done as follows:
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
[self dismissModalViewControllerAnimated:YES];
}
Instruments marks "selectContactViewController = [[ABPeoplePickerNavigationController alloc] init];" as leaking. Any idea why?
You might want to construct your Picker control like so:
ABPeoplePickerNavigationController* selectContactViewController = nil;
selectContactViewController = [[[ABPeoplePickerNavigationController alloc] init] autorelease];
selectContactViewController.peoplePickerDelegate = self;
[self presentModalViewController:selectContactViewController animated:YES];
When you present the modal view controller, it will retain the view on its own. That's how it's able to still pass you an instance of the view controller to your delegate. Best bet is to set the view controller to be autoreleased, so when it gets popped from the navigation controller, the NSAutoReleasePool will garbage collect it.
Just a comment - do you use any protocol like UINavigationControllerDelegate in the interface declaration?
I encountered a situation where just referencing this protocol caused a similar leak message.

is this lead to memory leak for iphone

Let me explain in detais
In appDidfinish()
{
preLoginNavController = [[PreLoginNavController alloc] initPreLoginNavController];
[window addSubview:[preLoginNavController view]];
}
then in preLoginViewController when user press a button
then i am doing this to go to view2
RootViewController *arootController= [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:arootController animated:YES];
if i do this [arootController release]; then i cant come form view 2
now in view 2 when back button is pressed
then i am doing this
[self.navigationController popToRootViewControllerAnimated:YES];
so i cannot release [arootController release] else when i go to back view app quits with no error
and i need a prelogin view before Rootview thats why i did like that now what should i do .. my app is working fine but i want to fix that leak :(
HEY
i am getting this message when i click back button in view 2 after push and release in preLogin(1st view)
objc[408]: FREED(id): message release sent to freed object=0x466a340
I think yes, is leaking arootController once you pop it.
yeah, there will have a leak. 2 suggested solutions are:
[arootController autorelease];
or after you do :
[self.navigationController pushViewController:arootController animated:YES];
you can release it.
A good practice is that : who increase the retain Count, should decrease it. and because aRootController is init in that class, it should be released there
Edit:
This should be the correct code if you want to use navigationController:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
self.preLoginNavController = [[[PreLoginNavController alloc] init] autorelease];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.mainItemListViewController];
[window addSubview:[self.navigationController view]];
[window makeKeyAndVisible];
}
then when you need to push:
[self.navigationController pushViewController:anotherViewController animated:YES];