Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide all modal view controllers

i've a login view presented as a ModelViewController and i have a register view presented as a NavigationControlloer on top of it:

Login (ModelViewController) ---->Register(NavigationController)

i'm presenting the Register view(CreateAccount) at the Loginview as follow:

createAccount= [[CreateAccount alloc] initWithNibName:@"CreateAccount" bundle:nil];

navController = [[UINavigationController alloc] initWithRootViewController:createAccount];

UIBarButtonItem *cancelButtun=[[UIBarButtonItem alloc]initWithTitle:@"Cancel" style:UIBarButtonItemStyleBordered target:self action:@selector(HideMe)];

UIBarButtonItem *registerButtun=[[UIBarButtonItem alloc]initWithTitle:@"Register" style:UIBarButtonItemStyleBordered target:self action:@selector(Register)];

createAccount.navigationItem.leftBarButtonItem = cancelButtun;
createAccount.navigationItem.rightBarButtonItem=registerButtun;
createAccount.title=@"Create Account";

[self presentModalViewController:navController animated:YES];

the login controller has the NSURLConnectionDelegate for booth the login and the register. when registration finishs i simply call the

[self dismissModalViewControllerAnimated:YES];

which will dismiss the registration view only.

i want to dismiss the login view also so i can go back to my main application.

like image 426
Kassem Avatar asked Dec 29 '11 18:12

Kassem


3 Answers

Calling dismissModalViewController will, if the current view controller did not present any modal controllers, call the method on its parent instead. Calling the method on a view controller will dismiss all presented modal view controller to that controller. To illustrate:

If you have three view controllers: vc1, vc2 and vc3 and vc1 is the main/currently used view controller.

  1. In vc1 you present modal vc2. In vc2 you then call dismiss, because there are no modal vcs presented from vc2, the dismiss message is passed to the parent (vc1) which dismisses vc2, and you're back at vc1.

  2. In vc1 you present modal vc2, then from vc2 present modal vc3. Calling dismiss in vc3 will send the message to its parent (vc2) which will dismiss vc3. To dismiss vc2 and vc3 at the same time, you need to call dismiss in vc1, this will dismiss all (both) modal view controllers. If dismissing animated, only the first one will be animated.

One of the best ways to solve this is to use a navigation controller through-out. i.e. instead of using modalViews initially to present login view, use navigationViewcontroller there itself. If you need to present registration page. Push that view. If you need to goto the initial view (i.e. apart from loginView or registrationView), then use popToRootViewControllerAnimated method in navigationViewcontroller.

like image 115
Srikar Appalaraju Avatar answered Oct 27 '22 16:10

Srikar Appalaraju


Check out my answer to a similar question here: Dismissing ModalViewController of ModalViewController

I am using pretty much the same thing as you in my app, and this solution works for me. Please be sure to read the comments as well, since one of the references changed with iOS5.

Edit: In order to dismiss a modal view that is presented over another modal view, you have to call dismissModalViewControllerAnimated: on the parent of the parent.

iOS <5.0

[[[self parentViewController] parentViewController] dismissModalViewControllerAnimated:YES];

iOS 5.0+ (must change all references to parentViewController to presentingViewController)

[[[self presentingViewController] presentingViewController] dismissModalViewControllerAnimated:YES];
like image 21
superjessi Avatar answered Oct 27 '22 17:10

superjessi


The primary problem at hand is that the login view controller is completely unaware of when the registration view is dismissed and we can handle that with delegation.

First declare a protocol and a delegate property on registration view controller.

@protocol CreateAccountDelegate;

@interface CreateAccount : UIViewController

@property (nonatomic, assign) id <CreateAccountDelegate> delegate;

@end

@protocol CreateAccountDelegate <NSObject>

- (void)createAccountViewControllerDidFinish:(CreateAccount *)controller;

@end

Next, make the login view controller the delegate of the registration controller.

createAccount = [[CreateAccount alloc] initWithNibName:@"CreateAccount" bundle:nil];
createAccount.delegate = self;

And implement -createAccountViewControllerDidFinish:

- (void)createAccountViewControllerDidFinish:(CreateAccount *)controller
{
    [self dismissModalViewControllerAnimated:YES];
}

Finally, when you dismiss from within the registration controller, message the delegate to inform it if your imminent dismissal.

[self.delegate createAccountViewControllerDidFinish:self];
[self dismissModalViewControllerAnimated:YES];

Now, having said all of that. May I suggest an alteration to your design? I would present the login view controller as part of a navigation controller from the get go. Then if the user chooses to register, just push the registration view on to the controller. This way, no matter where you dismiss from, it will only have to dismiss the main navigation controller.

like image 20
Mark Adams Avatar answered Oct 27 '22 18:10

Mark Adams