Leak when using autorelease? - iphone

Even though I release the results object using autorelease, the Leak tool it is showing 100% leak in leak instrument.
ResultsViewController *results = [[[ResultsViewController alloc]initWithNibName:
#"ResultsViewController1" bundle:nil] autorelease];
[results getscore:(int)score:(int)skippedwords:(int)crtwords];
[self.navigationController pushViewController:results animated:YES];

In "Instruments" it always show you the autoreleased objects as "leaks"
Do one thing alloc/release "results" by yourself. Never ever use "Autorelease" until unless you have to return the object to other class or method.
ResultsViewController *results = [[ResultsViewController alloc]initWithNibName: #"ResultsViewController1" bundle:nil];
[results getscore:score :skippedwords :crtwords];
[self.navigationController pushViewController:results animated:YES];
[results release];
Because you have already pushed this controller to navigation controller so you don't need its instance anymore. Happy Coding ;)

Related

Please help: UINavigationController and view controllers memory management

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).

pushViewController at didSelectRowAtIndexPath

I have the following code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
if (tvc == nil)
tvc = [[TopicViewController alloc] initWithNibName:#"TopicViewController" bundle:nil];
tvc.title = #"Topic";
tvc.topicId = [[results objectAtIndex:indexPath.row] objectForKey:#"id"];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:tvc animated:YES];
[tvc release];
}
So when I tap on the row it is able to bring this table view. Then I press navigate back and choose a different row, then the app crashes. I tried to see in the console for any error, but can't find any. What is wrong?
I believe your (tvc == nil) is returning NO because you released tvc but didn't set it to nil so next time this method is accessed, you try and push it as a view controller without allocating it again, hence the crash.
You can either remove the if (tvc == nil) check or release tvc and then set it to nil with [tvc release], tvc = nil;.
The other possibility is your results array is being released. Where is it initialised and have you declared a retain property for it? If so you can access it with [self.results objectAtIndex:...] which will guarantee it will stick around until your view controller is deallocated.
#Equinox i think you need to do something like this
tvc.title = [[NSString alloc] initWithFormat:#"Topic"];
tvc.topicId = [[NSString alloc] initWithString:[[results objectAtIndex:indexPath.row] objectForKey:#"id"]];
Edit: i think you are over releasing some objects in your TopicViewController class so your app is getting crash with out any message in the console. what you can do is build and analyze your project to check for any over releasing objects
You're always releasing, even if it's not allocated.
Assuming tvc is a declared property that retains an object, do
self.tvc = [[TopicViewController alloc] initWithNibName:#"TopicViewController" bundle:nil];
//....
self.tvc = nil;
[tvc release];
instead of
tvc = [[TopicViewController alloc] initWithNibName:#"TopicViewController" bundle:nil];
//....
[tvc release];
However, I wouldn't release the view controller and re-allocate it at all, because a memory allocation is expensive. I would just store one tvc object and reuse it, by modifying it according to the selected row.

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.

Memory management on the array initialized for UITabBarController

I am still learning the ropes of Objective C and iPhone development. My weak point is memory management - any help will be much appreciated.
In the code below, where can I release the NSMutableArray listOfViewControllers? Keep in mind the function createTabs can be called within the app multiple times and the tabs are recreated dynamically based on user input. This function is within a ViewController.
If i do [listofViewControllers release] just before exiting the function, the app crashes when I have to call createTabs again
If I use a convenience method like below:
NSMutableArray *listOfViewControllers = [NSMutableArray arrayWithCapacity:1]
instead of:
NSMutableArray *listOfViewControllers = [[NSMutableArray alloc] init]
it still crashes when createTabs is called again
-(void) createTabs
{
//TODO - memory management - where do you release this?
NSMutableArray *listOfViewControllers = [[NSMutableArray alloc] init];
if ([briefingsArray count] > 0)
{
//add briefing(s) tab(s)
for (Briefing *briefing in briefingsArray)
{
WebViewController *briefingViewController = [[WebViewController alloc] initWithBriefing: briefing];
[listOfViewControllers addObject:briefingViewController];
[briefingViewController release];
}
[listOfViewControllers addObject:alertViewController];
//add archives tab
NSString *archiveURL = [NSString stringWithFormat: ARCHIVEURL, DeviceID()];
UIViewController *archiveViewController = [[WebViewController alloc] initWithURL:ARCHIVEURL andTitle:#"Archives" andImage:#"archive_icon.png"];
[listOfViewControllers addObject:archiveViewController];
[archiveViewController release];
}
NSArray *oldlistOfViewControllers = [self.tabBarController viewControllers];
UIViewController *vcOld = [oldlistOfViewControllers objectAtIndex:[oldlistOfViewControllers count] -1];
[listOfViewControllers addObject:vcOld];
[self.tabBarController setViewControllers:listOfViewControllers
animated:YES];
}
My best guess is that it has nothing to do with tab bar controller. When you did not release the array, the controllers in the array would never be dealloc and there was no problem at all. So it's likely that the problem might come from deallocation of your WebViewController.
It looks like what you are creating here - listOfViewControllers - should be an instance variable of whatever object you are making here. Then you should alloc/init it inside the object's -init method, and release it in dealloc.
It is good practice (and usually necessary) to make an instance variable for anything you expect to exist after the end (or before the start) of a function call.
After [self.tabBarController setViewControllers:listOfViewControllers
animated:YES];, you can release your listOfViewControllers. Because tabBarController will retain this listOfViewControllers by copy policy.
You can see the UITabBarController reference about viewControllers property. This property adopts the copy policy.
#property(nonatomic, copy) NSArray *viewControllers

Does pushViewController retain the controller?

I am struggling to find out if pushViewController retains the controller, currently I have the following code (which works) ...
ColorController *colorController = [[ColorController alloc] initWithNibName:nibColor bundle:nil];
[[self navigationController] pushViewController:colorController animated:YES];
[colorController release];
but am considering removing the release and adding an autorelease ...
ColorController *colorController = [[[ColorController alloc] initWithNibName:nibColor bundle:nil] autorelease];
[[self navigationController] pushViewController:colorController animated:YES];
Much appreciated
Gary
This does nothing...
ColorController *colorController = [[ColorController alloc] initWithNibName:nibColor bundle:nil];
[[[self navigationController] pushViewController:colorController animated:YES] autorelease];
You are autoreleasing the return value of pushViewController:animated:, which is void.
Your first snippet is valid, and correct. pushViewController: does indeed retain the controller that is pushed.
Edit: In your updated code, there is little difference between the two samples. Both maintain proper retain counts. However, it is a "best practice" to avoid using autoRelease unless necessary (especially in a memory sensitive area, like the iPhone). This helps your application to maintain a more predictable and manageable memory footprint.
Yes, the view controller is retained.
There isn't a huge difference between the two code blocks you posted (at least the version I'm looking at -- other people probably saw an earlier version with a misplaced call to autorelease). You could use either one. It's a matter of style.
It sure does. Anytime you give one object to another SDK object like this, it will be retained. Though that second line isn't autoreleasing what you think. Usually you want the autorelease on the same line as the init for clarity sake.
ColorController *colorController = [[[ColorController alloc] initWithNibName:nibColor bundle:nil] autorelease];
[[self navigationController] pushViewController:colorController animated:YES];
If want to try, you should try this
id temp = [self.navigationController.viewControllers objectAtIndex:1];
[self.navigationController popToViewController:temp animated:YES];
you'll be navigated to any other previous ViewController that are available in the stack.