release after iPhone navigationController pushViewController - iphone

I am very confused at the following code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
RPSAdvisorViewController *pushThis = [[RPSAdvisorViewController alloc]init];
pushThis.opponentName = [opponentArray objectAtIndex:indexPath.row];
[self.navigationController pushViewController:pushThis animated:YES];
//[pushThis release];
}
The if the line [pushThis release] does not get commented out, the app would crash when I pop back out of that view. I thought I always need to released the viewControllers that I allocated, but this time the app won't let me.
I even tried testing for leaks in instruments like this without releasing pushThis, there are no leaks.
I am really confused, can some one tell me why I'm not suppose to release pushThis?
Edit1: The crash will produce this error message:
-[CALayer release]: message sent to deallocated instance 0x4e66b20
It appears that when the navigationController pops the view controller, it trys to send release to pushThis again, which was already released. If I don't release everything works perfectly, instruments does not show any leaks even if i repeatedly push and pop the view controller.

You have to release it because when you push view controller, navigation controller take ownership of that controller.
I think there might be some views hierarchy issue with your app.Can you please check that?

I can only guess that there is some problem with RPSAdvisorViewController. Can you try replacing it with a place-holder UIViewController and see what happens?

Related

Very strange behaviour of dealloc - not getting called

I have tested my all viewControllers dealloc methods. And all of them getting called properly on calling popViewControllerAnimated.
But only 1 controller's dealloc method not getting called. I am not able to figure out the issue.
While pushing to that controller I have properly written following code:
AController *contr = [AController alloc]initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:contr animated:YES];
[contr release];
and when I am coming back from controller I have written :
[self.navigationController popViewControllerAnimated:YES];
This is really strange behaviour because this code is written on many controllers and its working properly.
If it's not getting called it's still alive. Try to use instruments to find it. If you use the allocations tool in instruments you should be able to find the class (by name) in a list of allocations and see if it is still alive or not. You can even see by whom (I'm pretending that classes are people) it is retained.
If dealloc is not called you might have another object that retain it.
Check that object that might use this delegate do not retain it.
Hi I know this is an old post, but this answer may help someone stuck in my position. Spent a long time trying to find out why dealloc wasn't getting called. It turned out that I was not invalidating an NSTimer in my viewWillDisappear method and hence it was holding on to the retain count.
This great blog post is a must read for people in this situation:
http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/#comment-41302
I was having the similar issue;I wanted to show a UIViewController for like 3 seconds(copyright screen). So I was essentially calling the PushViewCOntroller and popViewController from the main file and the dealloc was not getting called when i was popping the view controller.
I then switched from pushViewCOntroller to
[self.navigationController presentModalViewController:copyrightView animated:NO];
and
[self.navigationController dismissModalViewControllerAnimated:NO];
and it started working.
I dont know how it can fix the issue; but it did.
For me using autorelease when allocating viewcontroller worked hope this helps someone
[[AController alloc]initWithNibName:nil bundle:nil]autorelease];
In my case, i have assigned circular ref object type with strong reference. Changing to weak type fixed this issue.
Try getting which object retained in memory using Instruments as said in other answers.

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.

ViewController Was Deallocated Unexpectedly

I have a very strange problem and I hope I can get some help.
I have ExpenseListViewController that has its fetechResultController, and once a row is selected from the tableview, the code push detailViewController to the stack.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Create and push a detail view controller.
ExpenseDetailVeiwController *detailViewController = [[ExpenseDetailVeiwController alloc] initWithStyle:UITableViewStyleGrouped];
selectedExpense = (Expense *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
// Pass the selected expense to the new view controller.
detailViewController.expense = selectedExpense;
detailViewController.delegate=self;
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
In the detailViewController I save the context, and the callbacks of the fetchResultController on the ExpenseListViewController get called, but sometimes, not always, the listController had been deallocated.
See error message on the console:
2010-07-15 18:04:50.404 FunMobile[6396:207] *** -[ExpenseListViewController controllerWillChangeContent:]: message sent to deallocated instance 0x3bc34e0
(gdb) continue
2010-07-15 18:04:52.188 FunMobile[6396:207] *** NSInvocation: warning: object 0x3bc34e0 of class '_NSZombie_ExpenseListViewController' does not implement methodSignatureForSelector: -- trouble ahead
2010-07-15 18:04:52.189 FunMobile[6396:207] *** NSInvocation: warning: object 0x3bc34e0 of class '_NSZombie_ExpenseListViewController' does not implement doesNotRecognizeSelector: -- abort
I thought the viewController in this case should only be dealloced if it is got popped off the stack, what might be wrong here? I set the breakpoint at the dealloc method of the ExpenseListViewController, it is never called, when this error happens.
This problem happens in both OS 3.1.3 and OS 4.0
Thanks in advance in your help.
If your app is using a lot of memory all of a sudden, then the operating system will start releasing objects, particularly view controllers that use a lot of memory.
Check your application's memory situation with Instruments.
Override -didReceiveMemoryWarning: to see if you are getting memory warnings. You can use this convenience method to start releasing unused objects.
But if your app is using a lot of memory all of a sudden, this can point to a design problem or a bug with your code. Use Instruments to track memory use throughout your app's lifespan.
Maybe you release the delegate in ExpenseDetailVeiwController?
This is a common mistake - you declare a non-retain property for the delegate and then release it in dealloc.

"[CALayer release]: message sent to deallocated instance" when dismissing modal view controller

I've been struggling with this for last few days and I cannot find any solution, so I ask you for advice.
I have two UIViewControllers: NewPostUIViewController and SettingsUIViewController. In the second one I have a field:
id<SettingsUIViewControllerDelegate> delegate
and the first one implements protocol
SettingsUIViewControllerDelegate
When a button is pressed the following code is executed in NewPostUIViewController:
SettingsUIViewController *settingsUIViewController = [[SettingsUIViewController alloc] initWithNibName:#"SettingsView" bundle:nil];
settingsUIViewController.title = NSLocalizedString(#"Settings", #"Settings view title");
settingsUIViewController.delegate = self;
[self presentModalViewController:settingsUIViewController animated:YES];
[settingsUIViewController release];
when I want to dismiss SettingsUIViewController I call (code in SettingsUIViewController):
[delegate settingsAreDone:sender];
and settingsAreDone looks following (code in NewPostUIViewController):
[self dismissModalViewControllerAnimated:YES];
This all concludes in:
[CALayer release]: message sent to deallocated instance 0x5a76840
I tried to debug the code by setting a breakpoint in the release methods of both view controllers, but these methods are called so often that it's hard to say what can be the cause of this problem.
Any ideas?
First, the error you're getting isn't indicating that -release is being sent to a view controller, so breakpoints in your view controllers won't help. The over-release is happening on a CALayer, which is likely part of the modal animation.
First, we start with some basics about the delegate. I don't feel great about this being the cause, but you should always start with the easy basics. Your SettingsUIViewController delegate property should be assign, not retain, so you avoid retain loops. That's probably correct already, but when it's not, you can wind up with cases where objects exist longer than you expect them to (and so can send messages after their targets have gone away). Again, probably not the issue, but easy to check and easy to fix.
Next, you should look at the stack trace at the crash. Who is calling [CALayer release]? A possible cause is that the owning view controller gets released before the animation stops. When you close the settings controller, do you immediately close the NewPost controller?

Trying to understand NavigationController retain count for ViewControllers on its stack

I have an UITableViewController as the rootViewController for my navigatorController.
When I press a table cell I do the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MessageHistory *msg = (MessageHistory *)[[self fetchedResultsController]objectAtIndexPath:indexPath];
ConversationViewController *chatController = [[ConversationViewController alloc]initWithNibName:#"ConversationView" bundle:nil andUser:msg.user];
[self.navigationController pushViewController:chatController animated:YES];
[chatController release];
But when I'm returning from the chatController (using the back button on the navbar) I get “EXC_BAD_ACCESS”
commenting
//[chatController release];
solves the problem. How? I thought when pushing to the navigationController adds a retain count and when pop from it release it?
Also I believe if I'm not including the release after pushing to the navcontroller I'm generating a leak.
Any idea what's happening here?
I've had this problem a few times, and almost went crazy trying to find the error.
In my case, I had a UIWebView in my second view with the UIViewController set as it's delegate. In my UIViewController dealloc method, I forgot to put webView.delegate = nil.
When the second UIViewController was popped and thus deallocated, the UIWebView was sending a message to it's delegate (the second UIViewController, which didn't exist anymore).
Don't know if this applies to you, but I spend days searching for this error, so perhaps it is of any help.