I have an app that navigates thru different views using the navigation controller. This is what I’m doing:
MapViewController *aMap = [[MapViewController alloc] initWithNibName:#"MapView"
bundle:nil ];
[self.navigationController pushViewController:aMap
animated:YES];
[aMap release];
At an user action, I want to go back to the first view. This is what I did:
-(void)alertView:(UIAlertView *)alertView
didDismissWithButtonIndex:(NSInteger)buttonIndex
{
[self.navigationController popToRootViewControllerAnimated:NO];
}
When I press a button that call the bellow method, my app goes as expected to the first view. But the problem arises when I press the “Home button” and try to reopen the app. Then, the app crash giving the following error:
2010-12-23 14:33:18.504 test[4549:307] *** -[MapViewController respondsToSelector:]: message sent to deallocated instance 0x5c26320
I understand that I sending a message to an instance of the object that does not exist, but I don’t find where is this happening
Do you have any recommendation?
Something is trying to send messages to the MapViewController after it's been deallocated.
Are they any objects that reference it - is it the delegate for any of its subviews, or does it receive any notifications, or anything like that?
If so, you need to make sure you unsubscribe from any notifications in the controller's dealloc method, and set any delegate parameters (on other objects) that reference the controller to nil.
Related
I have a UIViewController (call it NumberTwo) which I presented as a modal view controller from another UIViewController (call it NumberOne). NumberTwo contains a touchesBegan method which listens for touches, and it also has an accelerometer method which listens for device orientation changes in the x, y, or z direction. NumberTwo has a button called "Done" which, when tapped, dismisses itself as a modal view controller:
[self dismissModalViewControllerAnimated:NO];
But it seems as though it's still listening for touches, and it's still listening for accelerations. How can I completely free up NumberTwo when I dismiss it? I tried adding a release call as follows:
[self dismissModalViewControllerAnimated:NO];
[self release];
but that caused a EXEC_BAD_ACCESS.
Did you release the controller after you presented it? E.g. in your method in NumberOneController that presents it, do you have something like:
NumberTwoController * controller = [NumberTwoController alloc] init];
// do stuff to config controller
[self presentModalViewController: controller];
[controller release];
Unless you want to hang on to NumberTwoController for re-use, this would be the usual pattern. The presentModalViewController method ensures that the controller is retained while it's in use. It should then get tidied up when, within NumberTwoController, you call [self dismissModalViewControllerAnimated: NO].
I had a very similar issue that plagued me for days. It turned out that my view controller class wasn't being deallocated when I dismissed it because that view controller had an active NSTimer that wasn't being invalidated (stopped). I was able to kill the timer in viewDidDisappear.
Make sure you are releasing everything you use when you finish with it; The dealloc method is only called when the UIViewController and all of its properties/objects are no longer in use. Never use [self release]; you need to release it from the view controller that created it after you are finished with it.
I have a navigation based iPhone app.
When you press on a cell in the tableview a new UIViewController is pushed to the navigation stack. In this view controller I am setting a custom titleView in the viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
// Setup custom navigation title
[self setTitle:#"Mediaportal"];
navItem = [[NavigationBarTitleItemViewController alloc] initWithNibName:#"NavigationBarTitleItem" bundle:nil];
[navItem setTitle:[theServer name]];
[navItem setSubTitle:#""];
[self.navigationItem setTitleView:navItem.view];
…
}
Once I switch back to the RootViewController:
[self.navigationController popToRootViewControllerAnimated:YES];
the app crashes with the following error (NSZombieEnabled=YES):
*** -[CALayer retain]: message sent to deallocated instance 0x5a5fd80
From what I can see the RootViewController still tries to access the custom titleView, which was deallocated with the second view controller. Once I comment out the custom titleView part in my code the app works.
I tried to set the navigationItem.titleView to nil (as found in the apple docs) before the second ViewController is deallocated, but that doesn't help.
Do you have a hint what I can do to prevent this crash?
Thanks,
Mark.
I had this exact same error a month or so ago, exactly the same situation. It drove me NUTS.
I discovered that the viewController i was popping too hadn't been deallocated at all. I had a custom UIButton subclass added to that view however that had been deallocated when the second view had been pushed. So when popping back, the UIButton wasn't there.
Check the view you are popping back to, to ensure you've not got any classes that you are deallocating, or are being autoreleased without you knowing.
Hope this helps.
I finally found the solution for it (a quite simple one).
I have to alloc and init the navItem through its property then it is being retained:
self.navItem = [[NavigationBarTitleItemViewController alloc] initWithNibName:#"NavigationBarTitleItem" bundle:nil];
I'm trying to change view upon receive a push notification while the app is still running. I tried using this in the AppDelegate.m
-(void)application:(UIApplication *)application didRecieveNotification:(NSDictionary *)userInfo
{
TestClass *aTestClassViewController = [[TestClass alloc]initWithNibName:#"TestClass" bundle:nil];
[self presentModalViewController:aTestClassViewController animated:YES];
[aTestClassViewController release];
}
But it didn't work. I can't even start up the app again. so I'm guessing this is the wrong way to do it.
Any idea guys? I would appreciate it.
Solved***
I did it this way ->
I showed an alert view first (Which i needed anyways)
then used the method of
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
TestClass *aSelectionScreenViewController = [[TestClass alloc] initWithNibName:#"TestClass" bundle:nil];
[viewController presentModalViewController:aSelectionScreenViewController animated: YES];
[aSelectionScreenViewController release]; }
We're missing some context about your application, but your basic problem is that it's the application delegate object which is receiving the notification, not a view controller. That's why you can't just do [self presentModalViewController:someViewController];
I think it's the snippet from your own answer that gives what you need: your app delegate (presumably) has a 'viewController' member, which is the root view controller for the application. It is that viewController object you need to prod into doing whatever it is you need. In the app I'm looking at right now, I have a tabBarController member in the app delegate, and I show an alert view and/or change the selected tab index when a notification comes in.
I would have your app delegate call a function on your main view controller when a message comes in, and have that function show the alert view, then do whatever state changes you need to do to make the main view controller reflect the received notification.
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?
I have two view controllers: MyParentViewController and MyChildViewController.
The application starts with MyParent. I push the MyChild controller to the top of the navigation stack, so that the chain is like so:
MyParent > MyChild
I log the object ID of MyChild with NSLog(#"%p", self):
2009-11-20 05:08:29.305 MyApp[2213:207] MyChildViewController instance: 0x36afc20
When I press the back button from MyChild this pops MyChild off the stack and returns me to MyParent.
When I rotate the iPhone while viewing MyParent, my application crashes with the following error message:
2009-11-20 05:08:37.671 MyApp[2213:207] *** -[MyChildViewController _existingView]: message sent to deallocated instance 0x36afc20
I have no _existingView method or instance variable in MyChildViewController.
If I pop MyChild off the stack, I think the navigation controller will release it, and I presume that it would be set to nil, and that any messages sent to it would be ignored. Though that's not happening here, obviously.
Does anyone have any ideas why my application crashes on rotation?
Is there a way to find out what is sending the _existingView message to MyChild?
EDIT
Here's the code for pushing MyChild on the stack:
MyChildViewController *_myChildViewController = [[MyChildViewController alloc] initWithNibName:#"MyChildViewController" bundle:nil];
_myChildViewController.managedObjectContext = self.managedObjectContext;
_myChildViewController.title = [_xyz name];
[self.navigationController pushViewController:_myChildViewController animated:YES];
UIBarButtonItem *_backButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"MyChildViewBackBarButtonItemTitle", #"") style:UIBarButtonItemStyleDone target:nil action:nil];
self.navigationItem.backBarButtonItem = _backButton;
[_backButton release];
[_myChildViewController release];
EDIT 2
I think I may have solved this. I have an UISearchDisplayController added to the view controller nib via Interface Builder.
Originally, I set this to nil when the MyChild controller is sent -viewDidUnload, thinking it is usually enough to set IBOutlet instances to nil in this method. But this doesn't appear to be enough for my search display controller. When I release this in -dealloc I don't get the crash. Is this a bug, I wonder, or expected behavior?
There is a way to find out more about who called (found here):
[...] Also, by the time the app is
terminated due to the uncaught
exception there is no useful
backtrace. If you set a breakpoint on
objc_exception_throw the debugger will
break before the exception is thrown
and you'll have a useful backtrace. I
do this with a .gdbinit file. Create a
file named .gdbinit and place it in
your home directory. This is the
contents of mine:
fb -[NSException raise]
fb -[_NSZombie release]
fb szone_error
fb objc_exception_throw
It's also possible to set these kinds
of breakpoints in the Xcode
breakpoints window or in the debugger
console. [...]
But I assume that won't fix your problem... _existingView seems to be called by the framework when rotating the phone. The only line I can think of telling the framework to perform this on _myChildController is this one:
myChildViewController.managedObjectContext = self.managedObjectContext;
Doesn't it work without this?
_existingView is an internal variable of an UIViewController instance, defined in UIViewController.h
Maybe you are retaining your MyChildViewController someplace in your code.
I was struggling with this too, and the solution was similar to Alex Reynolds'. I release my UISearchDisplayController on -dealloc method, but it had to be before the [super dealloc]. If I release it after super deallocation, it still crashes.