Dismiss previous modal view controller in current

2019-02-15 04:34发布

I currently have 3 ViewControllers: LoginViewController, SignUpViewController and MainViewController.

When the user opens the app, LoginViewController will be presented. If its the user's first time using the app then they will have to sign up, the "Sign Up" button is in the LoginViewController. The "Sign Up" button will bring up the SignUpViewController.

Once the user finished signing up. The MainViewController will be presented.

What I am trying to do is. In the MainViewController there will be a "Log Out" button. When the user press it the MainViewController should be dismissed and LoginViewController should be there. The user should not see the SignUpViewController for the second time.

Here is what I have tried:

1) Dismiss SignUpViewController and present MainViewController in "sign up" button:

- (void) signUpClicked
{
MainViewController *mainViewController = [viewController.storyboard instantiateViewControllerWithIdentifier:@"MainViewController"];

        [viewController presentViewController:mainViewController animated:YES completion:^{
            [viewController dismissViewControllerAnimated:NO completion:^{

            }];

        }];
}

2) When MainViewController loads, dismiss SignUpViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    SignUpViewController *signUpViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"SignUpViewController"];
    [signUpViewController dismissViewControllerAnimated:NO completion:^{

    }];

}

5条回答
Melony?
2楼-- · 2019-02-15 05:14

SOLUTION: Modifying the current navigation stack

The neatest way to solve this problem is by accessing the navigation controller Navigation stack. The navigation controller knows the flow by storing the controllers in an array where it stacks on an on the controllers. You can modify this stack by removing the undesired view controller once is safe to do so, this stack is represented on the property called viewControllers(NSArray). The safe way is to remove it from the array after is not the current view controller (or the top one on the stack) which you can check by looking at the property visibleViewController

So your array should look like this when you already signedup and you are on the mainViewController: [loginVC,SignUpVC,MainVC]

That means MainVC is the visibleViewController and it is safe to modify the navigation stack as long as you keep the same visibleViewController as the last item on your array.

Since is not a Mutable Array just assign a new array to the viewControllers property with this [loginVC,MainVC]. I will recommend at least taking a peak to the documentation on UINavigationController.

查看更多
Explosion°爆炸
3楼-- · 2019-02-15 05:20

presentViewController can get you a long ways, but maybe you should roll your own Container View Controller. They're pretty dang easy! The UIContainerViewControllerProtectedMethods category on UIViewController outlines what methods you can/should use.

The basic gist is you have a container View Controller that adds child View Controllers to itself and their views as subviews of its own view. The main method that does the heavy lifting is:

...   transitionFromViewController:(UIViewController *)fromViewController
                  toViewController:(UIViewController *)toViewController
                          duration:(NSTimeInterval)duration
                           options:(UIViewAnimationOptions)options
                        animations:(void (^)(void))animations
                        completion:(void (^)(BOOL finished))completion

In the animations section, you can do whatever sort of movement you want. In your case, you would want to put the LoginViewController's view behind the MainViewController's view, and move the MainViewController's view offscreen. You get to supply your own animation options, so the appearance will move similarly to how dismissViewController looks now.

It's a bit more overhead to get set up, but View Controller Containment gives you a lot of flexibility and power.

查看更多
萌系小妹纸
4楼-- · 2019-02-15 05:22

Got it. I passed the SignUpViewController to the MainViewController and dismiss the SignUpViewController in the MainViewController.

For anyone else who had the same question as me.

SignUpViewController.m

- (void) signUpButtonClicked
{
        MainViewController *mainViewController = [viewController.storyboard instantiateViewControllerWithIdentifier:@"MainViewController"];
        mainViewController.signUpViewController = viewController;

        [viewController presentViewController:mainViewController animated:YES completion:^{            
        }];
}

MainViewController.m

- (IBAction)logoutClicked:(id)sender
{

    [self dismissViewControllerAnimated:YES completion:^{

        [self.signUpViewController dismissViewControllerAnimated:NO completion:^{

        }];

    }];
}
查看更多
5楼-- · 2019-02-15 05:31

This worked for me; it was extremely tedious getting the order correct.

DestinationViewController *vc = [[UIStoryboard storyboardWithName:@"Main_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:@"DestinationView"];

UIViewController* presentingViewController = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
    [presentingViewController presentViewController:vc animated:YES completion:nil];

}];
查看更多
来,给爷笑一个
6楼-- · 2019-02-15 05:33

This wasn't part of your question, but you should consider using a UINavigationController because it's probable that you will have to show new views from your MainViewController.

The architecture I would use is the next:

  • UINavigationController
    • LoginViewController (RootViewController)
      • SignupViewController (Modal)
    • MainViewController (Push)

So your first view controller is the LoginViewController.

In your SignupViewController, you implements the next protocol:

@class SignupViewController;
@protocol SignupViewControllerDelegate : NSObject
@required
 - (void)signupViewController:(SignupViewController*)viewController didSignupWithData:(id)customData;
 - (void)signupViewControllerDidCancel:(SignupViewController*)viewController;
@end

The customData object is only useful if you need to pass data from your SignupViewController to your MainViewController.

And you add this property to your SignupViewController

@interface SignupViewController : UIViewController
@property (nonatomic, assign) id <SignupViewControllerDelegate> delegate;
...
@end

Your LoginViewController now has to implement the protocol you just created.

@interface LoginViewController : UIViewController <SignupViewControllerDelegate>
...
@end

And you should implement those methods like this

@implementation LoginViewController

- (void)signupViewController:(SignupViewController*)viewController didSignupWithData:(id)customData {
    // You can dismiss the SignUpViewController before pushing your next view
    [self dismissViewControllerAnimated:NO completion:^{
        // You can store the data you received from the SignupViewController

        // Push your next view controller here
        [self performSegueWithIdentifier:@"myIdentifier" sender:nil];

        // Or this if you don't use Storyboard
        MainViewController *vc = [[MainViewController alloc] initWithCustomData:customData];
        [self.navigationController pushViewController:vc animated:YES];
    }];
}

- (void)signupViewControllerDidCancel:(SignupViewController*)viewController {
        // The user canceled the Signup operation, just dismiss the viewController
        [self dismissViewControllerAnimated:YES completion:nil];
}

@end

I'm explaining a little this code ^^ In your SignupViewController, when the user clicks on the button that ends the signup process, you call this method

[self.delegate signupViewController:self didSignupWithData:myCustomData];

Or if he cancels

[self.delegate signupViewControllerDidCancel:self];

With this method, your SignupViewController will be removed when you present your MainViewController. And when the user logouts, you will have to call this method in your MainViewController :

[self.navigationController popViewControllerAnimated:YES];

As your SignupViewController is already dismissed, you will be redirected yo your LoginViewController directly.

查看更多
登录 后发表回答