ViewController Was Deallocated Unexpectedly - iphone

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.

Related

release after iPhone navigationController pushViewController

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?

UIViewController not being dealloc-ed under the new ARC memory management

I am pushing my UIViewController subclass onto the navigation stack; however, since it is being retained by the navigationController, I 'release' my pointer to it after pushing it onto the stack so that when it is eventually popped the viewController will be dealloc-ed.
However, it's not working, the dealloc method for the viewController is never called. The code looks something like this:
MyViewController *newViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"foo"];
[self.navigationController pushViewController:newViewController animated:YES];
newViewController = nil;
Even in the following code, my newViewController is not being dealloc-ed:
MyViewController *newViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"foo"];
newViewController = nil;
From what I understand, under the new Automatic Reference Counting (ARC) system, objects are dealloc-ed once nothing points to it. I put a NSLog method in the dealloc method of the viewController that is being created, but it is never called.
What am I missing here?!
Thanks for reading my first post on stack overflow :)
**EDIT:**
I apologise. I tried the second piece of code wrapped in an autorelease pool and it was deallocated. I then tried it without the autorelease pool and it deallocated properly too. I don't know what happened last night.
(2nd edit: and now its stopped working again. fffffffuuuuuuuuuuuu)
In your first example, it would be very odd if the new view controller were deallocated, since you just pushed it onto the navigation controller, and thus the navigation controller has a strong reference to it. The object will only be deallocated when ALL strong references are gone.
In your second example, it's possible that the returned object still has pending releases from autorelease calls that were performed internal to the implementation of instantiateInitialViewController. Thus, until the current autorelease pool is drained, you wouldn't see it disappear. Further, it's possible that the UIStoryboard class caches the returned object as an optimization.
In short, even with ARC you still cannot assume that objects you receive from framework methods will be deallocated immediately when you're done with them, because you cannot guarantee that autorelease was not used in that method's implementation.

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.

"[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?

Iphone - is controller freed after push?

is my UIViewController freed when i call another controller ?
How to release memory of controller when i push to another controller ? i take more than 40Mo and application leave because of LOW MEMORY(No leak).
[self.navigationController pushViewController:[[MainListController alloc] init:self] animated:NO];
#interface MainListController : UIViewController
...
- (id)init: (id)ref;
when i call on init function the dealloc of controller i was :
[ref dealloc];
i've this error :
objc[70754]: FREED(id): message isEqual: sent to freed object=0xe216b0
Program received signal: “EXC_BAD_INSTRUCTION”.
(void)dealloc {[super dealloc];}
You cannot (and should not) release/dealloc a parent view controller when pushing a new one onto the navigation stack. You can unload the view by responding to the didReceiveMemoryWarning message.
There are several other problems with your code:
Never ever call [obj dealloc] manually. Always use [obj release].
Your init method name should be more descriptive as to not conflict with the predefined init method. You should also (possibly) strongly type the ref argument if you need to use it. Something like (id)initWithParent:(UIViewController*)ref would be better.
Your code is leaking a MainListController object, since you are alloc/init'ing it and then handing it to navigationController. Change your code to [[[MainListController alloc] initWithParent:self] autorelease].
No, you can't dealloc UIViewControllers that are not visible. What happens when the controllers on top pop off the navigation controller? What would the OS display then?
Instead you should implement the didReceiveMemoryWarning method in all your controllers. These should release (not dealloc) as much cached data as possible. Anything that you can recalculate or bring back in from disk should be considered.
This is better than just deallocing views that are not visible as you really don't know how much memory is available in advance. On an iPhone 3GS you might have plenty of memory left even when using 40Mb.