dismissModalViewControllerAnimated: (and dismissViewControllerAnimated) crashing in iOS 5
Asked Answered
M

2

9

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
}    
Mamelon answered 19/10, 2011 at 12:53 Comment(5)
As I suspected, removing the animation from the viewDidLoad method of loginController has no bearing on the issue. Grasping at straws here.Mamelon
That sure is strange. Are you sure you are not releasing loginController at any place other than [loginController release] ?Gonsalves
I will check to be sure, but changing the animation flag and leaving all other code as is causes a crash. I would think a management problem would present itself regardless of the animation, but this is inexplicable at the moment, so I will surely check.Mamelon
@Manali, there are other methods that instantiate that class, but none exist at the time of this crash. I will edit my post to show the exact flow.Mamelon
Just put in a NSLog to check for low memory warnings that might be releasing the view, and I have no warnings and no log appears.Mamelon
B
4

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

Bookish answered 19/10, 2011 at 15:32 Comment(3)
Looks like I don't have to go through and change all of my presentModalViewController calls to presentViewController calls like I thought. Whew, I can save that for the next release.Mamelon
I had the same problem, just moved it to DidBecomeActive and submitted the fix in order to have a bug-free version in the Store... No idea what lifecycle changes Apple did...Bookish
it doesn't help me with : #11833481Dkl
W
2

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.

Whatever answered 11/1, 2012 at 23:44 Comment(1)
I have the showLoginPanel on (IBAction) and the login close as a callback, but in main thread, also the logincontroller relase in dealloc only and I have the crach : #11833481Dkl

© 2022 - 2024 — McMap. All rights reserved.