popping and pushing view controllers in same action
Asked Answered
T

8

49

is is possible to pop a view off the navigation stack and then push another straight onto it?

I'm trying to implement a flat hierarchy for this section and would like to have a segmented controller but I can't make the segmented controller look anything liked I want, hence why I'm trying to use the navigation controller.

When a button is clicked I executed this code:

[[self navigationController] popViewControllerAnimated:YES];
        MapsViewController *aViewController = [[MapsViewController alloc]
                                               initWithNibName:@"MapsViewController" bundle:nil];
[self.navigationController pushViewController:aViewController animated:NO];
[aViewController release];

It's popping off ok but theres no sign of any pushing! Any help would be appreciated.

Triangulation answered 29/7, 2011 at 12:8 Comment(0)
P
46
 MapsViewController *aViewController = [[MapsViewController alloc]
                                        initWithNibName:@"MapsViewController" bundle:nil];
     // locally store the navigation controller since
     // self.navigationController will be nil once we are popped
 UINavigationController *navController = self.navigationController;

     // retain ourselves so that the controller will still exist once it's popped off
 [[self retain] autorelease];

     // Pop this controller and replace with another
 [navController popViewControllerAnimated:NO];//not to see pop

 [navController pushViewController:aViewController animated:YES];//to see push or u can change it to not to see.

Or

 MapsViewController *aViewController = [[MapsViewController alloc]
                                        initWithNibName:@"MapsViewController" bundle:nil];


UINavigationController *navController = self.navigationController;

//Get all view controllers in navigation controller currently
NSMutableArray *controllers=[[NSMutableArray alloc] initWithArray:navController.viewControllers] ;

//Remove the last view controller
[controllers removeLastObject];

//set the new set of view controllers
[navController setViewControllers:controllers];

//Push a new view controller
[navController pushViewController:aViewController animated:YES];
Protero answered 29/7, 2011 at 12:15 Comment(9)
It's not just that I can't see the push happening, it isn't happening. At least there's no evidence that it's happened.Triangulation
It's an instance of MapViewControllerTriangulation
awesome, works brilliantly. Could you please explain why you have to retain self?Triangulation
otherwise it will release and move to parentViewcontroller.so eventhough u perform pushing u can't seeProtero
No working anymore for iOS 8 - the autorelease in [[self retain] autorelease]; cause a crash.Senescent
@TomerPeled Dude take a look at the OR answer. it doesn't have the autorelease.Protero
Sorry but also the second solution doesn't work on iOS8Senescent
The following solution works good (taken from #410971): IViewController *newVC = [[UIViewController alloc] init]; // Replace the current view controller NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]]; [viewControllers removeLastObject]; [viewControllers addObject:newVC]; [[self navigationController] setViewControllers:viewControllers animated:YES];Senescent
Upvote because of Second Solution is working for me thanks @Protero For sharing this.Handyman
A
34

In Swift:

let newVc = UIViewController()
var vcArray = self.navigationController?.viewControllers
vcArray!.removeLast()
vcArray!.append(newVc)
self.navigationController?.setViewControllers(vcArray!, animated: false)

In case newVc exists in a Storyboard:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let newVc = storyboard.instantiateViewControllerWithIdentifier("YourViewControllerIdentifier") as! UIViewController
var vcArray = self.navigationController?.viewControllers
vcArray!.removeLast()
vcArray!.append(newVc)
self.navigationController?.setViewControllers(vcArray!, animated: false)
Amasa answered 26/10, 2015 at 4:15 Comment(2)
Rodrigo, salvou meu dia. vlw!Sarabia
Thanks, saved my day :)Meetly
H
31

Taken from https://stackoverflow.com/users/1619554/tomer-peled 's solution, so others can find it more easily.

This appears to be the best way to do it for iOS8:

UIViewController *newVC = [[UIViewController alloc] init]; // Replace the current view controller 
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
[viewControllers removeLastObject]; 
[viewControllers addObject:newVC]; 
[[self navigationController] setViewControllers:viewControllers animated:YES];
Hautesavoie answered 6/11, 2014 at 21:47 Comment(1)
This solution worked for me with iOS 8 and not the selected answer. Thanks!Patisserie
P
10

Swift 4 :

self.navigationController.setViewControllers[].. doesn't worked out for me. But I am able to solve the issue by holding a navigation controller in an instance variable and do push/pop operation. Thus, silently able to change controller without glitch.

  guard let navigationVC = self.navigationController else { return }  
    navigationVC.popViewController(animated: false)
    navigationVC.pushViewController(myNewVC, animated: false)
Pesky answered 9/1, 2018 at 11:1 Comment(0)
S
7

You can use this code to pop or push your controller.

For objective c

bool alreadyPushed = false;    
//Check if the view was already pushed
NSMutableArray *viewControllers;
if ( (viewControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers])) {

    for (UIViewController *aViewController in viewControllers) {

        if ([aViewController isKindOfClass:[YourControllerName class]]) {
            NSLog(@"pop your view controller");
            [self.navigationController popToViewController:aViewController animated:YES];
            alreadyPushed = true;
            break;
        }
    }
}

//Push Fresh View
if( alreadyPushed == false) {

    NSLog(@"push your view controller");
    YourControllerName *YourControllerObject = [[YourControllerName alloc]initWithNibName:@"YourNibName" bundle:nil];        
    [self.navigationController pushViewController:YourControllerObject animated:YES];

}

For Swift

  var alreadyPushed = false            
        //Check if the view was already pushed
        if let viewControllers = self.navigationController?.viewControllers {
            for viewController in viewControllers {                    
                if let viewController = viewController as? YourControllerName {                                               
                    self.navigationController?.popToViewController(viewController, animated: true);                        
                    print(" Push Your Controller")
                    alreadyPushed = true
                    break                        
                }
            }
        }                        
        if alreadyPushed == false {                
            let YourControllerObject = self.storyboard?.instantiateViewControllerWithIdentifier("YourControllerIdentifire") as! YourControllerName             
            self.navigationController?.pushViewController(YourControllerObject, animated: true)

        }
Santa answered 13/1, 2016 at 11:26 Comment(0)
P
0
BOOL Present = NO;

fifthViewController * fifthVC = [self.storyboard instantiateViewControllerWithIdentifier:@"homeController"];


for (UIViewController* viewController in self.navigationController.viewControllers) {

    //This if condition checks whether the viewController's class is MyGroupViewController
    // if true that means its the MyGroupViewController (which has been pushed at some point)
    if ([viewController isKindOfClass:[fifthViewController class]] )
    {

        // Here viewController is a reference of UIViewController base class of MyGroupViewController
        // but viewController holds MyGroupViewController  object so we can type cast it here
        fifthViewController *groupViewController = (fifthViewController*)viewController;
        [self.navigationController popToViewController:groupViewController animated:NO];
        Present=YES;
    }

}

if(Present==NO)
{
    [self PushAnimation];
    [self.navigationController pushViewController:fifthVC animated:NO];

    Present=YES;
}
Piezoelectricity answered 30/5, 2016 at 10:58 Comment(0)
E
0

Swift 3.0

In case someone wants to go deep into the view hierarchy:

                //Go back to desired viewController and then push another viewController
                var viewControllers = self.navigationController!.viewControllers
                while !(viewControllers.last is MyViewControllerClass) {
                    viewControllers.removeLast()
                }
                // go to new viewController
                let anotherViewController = AnotherViewController(nibName: "AnotherViewController", bundle: nil)
                viewControllers.append(anotherViewController)
                self.navigationController?.setViewControllers(viewControllers, animated: true)
Efrenefron answered 13/7, 2017 at 12:12 Comment(0)
P
0

This can be achieved by adding an extension on UINavigationController as follows:

extension UINavigationController {
    
    func popAndPushViewController(_ viewController: UIViewController, animated: Bool) {
        pushViewController(viewController, animated: animated)
        var viewControllersCopy = viewControllers
        if viewControllersCopy.count-2 >= 0 {
            viewControllersCopy.remove(at: viewControllersCopy.count-2)
        }
        setViewControllers(viewControllersCopy, animated: false)
    }        
}

And use popAndPushViewController in place of pushViewController method of navigationController instance on UIViewController.

As an example:

let aViewController = UIViewController() // Create instance of appropriate VC
navigationController?.popAndPushViewController(aViewController, animated: true)
Polygraph answered 16/2, 2024 at 13:46 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.