The -popToViewController
is used to pop view controllers OFF the stack, down to one that already exists. Your UINavigationController
has a stack of ViewControllers (stored in the viewControllers
property), when you popToViewController
, you're going to want to pass one of the elements in that array as the first argument.
What you most likely want to do in this case is use -popViewControllerAnimated:
, which will remove the top ViewController
from the stack
[self.navigationController popViewControllerAnimated:YES];
You're allocating the RootViewController right there. It does not exist in the navigation controller's stack, so no matter how far you pop, you won't reach it.
id viewController = [[RootViewController alloc] init];
// ...
[self.navigationController pushViewController:viewController animated:YES];
// ...
// Here is the initial view controller, not in the stack.
[self.navigationController popToViewController:viewController animated:YES];
I had this problem recently and solved with something like this...
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
If you are using Storyboads, use this segue:
@implementation PopToControllerSegue
- (void) perform
{
UIViewController *sourceViewController = (UIViewController *)self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *)self.destinationViewController;
for (UIViewController* controller in sourceViewController.navigationController.viewControllers) {
if ([controller isKindOfClass:destinationViewController.class]) {
[sourceViewController.navigationController popToViewController:controller animated:YES];
return;
}
}
NSLog(@"PopToControllerSegue has failed!");
}
@end
When using Push Segues you can easily go back to the root using this method:
[self.navigationController popToRootViewControllerAnimated:YES];
When using Modal Segues (because of the word dismiss in the question and as a general reference) you can dismiss
the view controller using this method:
[self dismissViewControllerAnimated:YES completion:nil];
The UINavigationController
has a stack of ViewControllers
which is stored in the viewControllers(NSArray) property. Enumerate to the required ViewController
and pop to that ViewController
.
Following code should solve the problem.
-(IBAction)dismissView
{
NSArray *array = self.navigationController.viewControllers;
for (id controller in array) {
if ([controller isKindOfClass:[RootViewController class]]) {
[self.navigationController popToViewController:controller animated:YES];
}
}
}
Try this one line solution.
Swift 4+:
self.navigationController?.popToViewController ((self.navigationController?.viewControllers[1]) as! Your_ViewController, animated: true)
Objective-C:
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
Swift 4
For anyone still looking for a better solution that doesn't involve the UINavigationController stack indexes, which is getting more problematic with bigger navigation stack - here's the easiest way to solve this:
if let destinationViewController = navigationController?.viewControllers
.filter(
{$0 is DestinationViewController})
.first {
navigationController?.popToViewController(destinationViewController, animated: true)
}
In my case the problem was that I was in the root ViewController and this works only for VCs that are stacked over it. To pop to the RootViewController use
navigationController?.popToRootViewController(animated: true)
self.navigationController?.present(viewControllers, animated: true, completion: nil)
Before popToViewController, check that NavigationController contains your ViewController:
if !navigationController.viewControllers.filter({ $0 == viewController}).isEmpty {
navigationController.popToViewController(viewController, animated: true)
}