I can't find any logical explanation, but the fact remains that, in iOS 5 (xCode 4.2), if I presentModalView:* animated:YES, I can call dismissModalViewAnimated:* fine, but if I call presentModalView:* animated:NO, then calling the dismiss method crashes. (This works the same if I use the new presentViewController:animated:completion: + dismissViewControllerAnimated:). I am going TRY to work around this for now (I don't want the presentation animated) and report a bug to Apple, but I have been beating my head on this for a while. Any and all suggestions are welcome. Not much out there on iOS 5, so please help if you can. Sample code that does not crash in iOS 4 or iOS 5:
LoginController *loginController = [[LoginController alloc] initWithNibName:@"LoginControllerGG" bundle:nil];
[self presentModalViewController:loginController animated:YES];
[loginController release];
...
[self dismissModalViewControllerAnimated:YES];
This will crash in iOS 5 with EXC_BAD_ACCESS on the dismiss call:
LoginController *loginController = [[LoginController alloc] initWithNibName:@"LoginControllerGG" bundle:nil];
[self presentModalViewController:loginController animated:NO];
[loginController release];
...
[self dismissModalViewControllerAnimated:YES]; //crashes with EXC_BAD _ACCESS
One note: I have an animation within the loginController that happens on viewDidLoad. Going to see if taking that out changes anything, but I wanted to get this out there since I need a solution asap.
[Edit] Full code flow... In AppDelegate, application:didFinishLaunchingWithOptions:
if (!loggedIn) [myViewController showLoginPanel];
In myViewController:
- (void)showLoginPanel {
LoginController *loginController = [[LoginController alloc] initWithNibName:@"LoginControllerGG" bundle:nil];
if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]) {
[self presentViewController:loginController animated:NO completion:nil];
} else {
[self presentModalViewController:loginController animated:NO]; //iOS 4 works fine with or without animation
}
[loginController release];
}
In loginController:
- (IBAction)closeLoginWindow {
[[NSNotificationCenter defaultCenter] postNotificationName:@"CloseLoginWindow" object:nil];
} //doing it this way because calling on the self.parentViewController doesn't work
Back in myViewController:
- (void) viewDidLoad
...
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeLoginWindow) name:@"CloseLoginWindow" object:nil];
...
- (void)closeLoginWindow {
if ([self respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]) {
[self dismissViewControllerAnimated:YES completion:nil]; //iOS 5 crashes only if presentation was not animated
} else [self dismissModalViewControllerAnimated:YES]; //deleting the previous condition, iOS 5 still crashes if presentation was not animated
}
In iOS5 the managing of the lifecyle somehow changed and I cannot explain that issue in detail. Anyway, the fix is to postpone that workflow from applicationDidFinishLaunchingWithOptions to applicationDidBecomeActive. It seems that something isn't initialized right at the call of applicationDidFinishLaunchingWithOptions.
- (void)applicationDidFinishLaunchingWithOptions:... {
// in order to do this only at launching, but not on every activation
// Declaration as property for example
applicationDidLaunch = YES;
}
- (void) applicationDidBecomeActive:(UIApplication *)application {
if (applicationDidLaunch) {
applicationDidLaunch = NO;
[Start your login Workflow with modal view presenting here]
}
}
Curious to ur feedback :)....
I will add my 2 cents : i had ImagePickerController and got its dismissing working only when i did not release the picker manually (IOS 5 SDK).
So. for your case i could offer such workaround : 1. remove line - [loginController release]; 2. to prevent memory leaks add loginController as a property to your current controller and release it only in dealloc() of current controller :
@interface myViewController : UIViewController
@property (nonatomic, retain) LoginController *loginController;
@end
...
@implementation myViewController
- (void)showLoginPanel {
self.loginController = [[LoginController alloc] initWithNibName:@"LoginControllerGG" bundle:nil];
// ... something goes here
}
-(IBAction)loginClose()
{
// this should close all windows as far as you call it from current (main) controller
[self dismissModalViewControllerAnimated:YES];
// ... then anything you want EXCEPT [loginController release];
}
-(void)dealloc()
{
[loginController release];
}
@end
Good luck :)
P.S. I have just written this so it is just an idea how to cheat it. Somebosy may correct me ... though anyway it worked for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With