iPhone - dismiss multiple ViewControllers

后端 未结 22 2912
粉色の甜心
粉色の甜心 2020-11-28 04:46

I have a long View Controllers hierarchy;

in the first View Controller I use this code:

SecondViewController *svc = [[SecondViewController alloc] i         


        
相关标签:
22条回答
  • 2020-11-28 05:36

    For Swift 3.0+

    self.view.window!.rootViewController?.dismissViewControllerAnimated(false, completion: nil)
    

    This will dismiss all presented view controllers on your rootviewcontroller.

    0 讨论(0)
  • 2020-11-28 05:37

    Say your first view controller is also the Root / Initial View Controller (the one you nominated in your Storyboard as the Initial View Controller). You can set it up to listen to requests to dismiss all its presented view controllers:

    in FirstViewController:

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // listen to any requests to dismiss all stacked view controllers
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissAllViewControllers:) name:@"YourDismissAllViewControllersIdentifier" object:nil];
    
        // the remainder of viewDidLoad ...
    }
    
    // this method gets called whenever a notification is posted to dismiss all view controllers
    - (void)dismissAllViewControllers:(NSNotification *)notification {
        // dismiss all view controllers in the navigation stack
        [self dismissViewControllerAnimated:YES completion:^{}];
    }
    

    And in any other view controller down the navigation stack that decides we should return to the top of the navigation stack:

    [[NSNotificationCenter defaultCenter] postNotificationName:@"YourDismissAllViewControllersIdentifier" object:self];
    

    This should dismiss all modally presented view controllers with an animation, leaving only the root view controller. This also works if your initial view controller is a UINavigationController and the first view controller is set as its root view controller.

    Bonus tip: It's important that the notification name is identical. Probably a good idea to define this notification name somewhere in the app as a variable, as not to get miscommunication due to typing errors.

    0 讨论(0)
  • 2020-11-28 05:37

    Swift extension based upon the above answers:

    extension UIViewController {
    
        func dismissUntilAnimated<T: UIViewController>(animated: Bool, viewController: T.Type, completion: ((viewController: T) -> Void)?) {
            var vc = presentingViewController!
            while let new = vc.presentingViewController where !(new is T) {
                vc = new
            }
            vc.dismissViewControllerAnimated(animated, completion: {
                completion?(viewController: vc as! T)
            })
        }
    }
    

    Swift 3.0 version:

    extension UIViewController {
    
        /// Dismiss all modally presented view controllers until a specified view controller is reached. If no view controller is found, this function will do nothing.
    
        /// - Parameter reached:      The type of the view controller to dismiss until.
        /// - Parameter flag:         Pass `true` to animate the transition.
        /// - Parameter completion:   The block to execute after the view controller is dismissed. This block contains the instance of the `presentingViewController`. You may specify `nil` for this parameter.
        func dismiss<T: UIViewController>(until reached: T.Type, animated flag: Bool, completion: ((T) -> Void)? = nil) {
            guard let presenting = presentingViewController as? T else {
                return presentingViewController?.dismiss(until: reached, animated: flag, completion: completion) ?? ()
            }
    
            presenting.dismiss(animated: flag) {
                completion?(presenting)
            }
        }
    }
    

    Completely forgot why I made this as it is incredibly stupid logic considering most of the time a modal view controller's presenting view controller is UITabBarController rendering this completely useless. It makes much more sense to actually acquire the base view controller instance and call dismiss on that.

    0 讨论(0)
  • 2020-11-28 05:38
      id vc = [self presentingViewController];
      id lastVC = self;
      while (vc != nil) {
        id tmp = vc;
        vc = [vc presentingViewController];
        lastVC = tmp;
      }
      [lastVC dismissViewControllerAnimated:YES completion:^{
    }];
    
    0 讨论(0)
  • 2020-11-28 05:39

    Use this generic solution to solve this issue:

    - (UIViewController*)topViewController
    {
        UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
        while (topController.presentedViewController) {
            topController = topController.presentedViewController;
        }
        return topController;
    }
    
    
    - (void)dismissAllModalController{
    
        __block UIViewController *topController = [self topViewController];
    
        while (topController.presentingViewController) {
            [topController dismissViewControllerAnimated:NO completion:^{
    
            }];
            topController = [self topViewController];
        }
    }
    
    0 讨论(0)
  • 2020-11-28 05:41

    First of all Oscar Peli thanks for your code.

    To start your navigationController at the beginning, you could make it a little more dynamic this way. (in case you don't know the number of ViewControllers in stack)

    NSArray *viewControllers = self.navigationController.viewControllers;
    [self.navigationController popToViewController: [viewControllers objectAtIndex:0] animated: YES];
    
    0 讨论(0)
提交回复
热议问题