48

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.

Josh
  • 3,445
  • 5
  • 37
  • 55

7 Answers7

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];
  • 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. – Josh Jul 29 '11 at 12:22
  • It's an instance of MapViewController – Josh Jul 29 '11 at 12:33
  • awesome, works brilliantly. Could you please explain why you have to retain self? – Josh Jul 29 '11 at 12:40
  • otherwise it will release and move to parentViewcontroller.so eventhough u perform pushing u can't see – Vijay-Apple-Dev.blogspot.com Jul 29 '11 at 12:51
  • No working anymore for iOS 8 - the autorelease in [[self retain] autorelease]; cause a crash. – Tomer Peled Aug 17 '14 at 18:30
  • @TomerPeled Dude take a look at the OR answer. it doesn't have the autorelease. – Vijay-Apple-Dev.blogspot.com Aug 18 '14 at 05:00
  • Sorry but also the second solution doesn't work on iOS8 – Tomer Peled Aug 18 '14 at 06:47
  • 1
    The following solution works good (taken from http://stackoverflow.com/questions/410471/how-can-i-pop-a-view-from-a-uinavigationcontroller-and-replace-it-with-another-i/1787323?noredirect=1#comment39558837_1787323): 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]; – Tomer Peled Aug 18 '14 at 17:50
  • Upvote because of Second Solution is working for me thanks @Vijay-Apple-Dev.blogspot.com For sharing this. – Yogesh Patel Jul 02 '19 at 09:20
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)
Rodrigo Pinto
  • 2,384
  • 22
  • 23
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];
Community
  • 1
  • 1
Peter Johnson
  • 3,764
  • 1
  • 23
  • 27
9

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)
shippo7
  • 407
  • 5
  • 15
byJeevan
  • 3,728
  • 3
  • 37
  • 60
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)

        }
Vikram Pote
  • 5,433
  • 4
  • 33
  • 37
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;
}
node_modules
  • 4,790
  • 6
  • 21
  • 37
Vikash Kumar
  • 642
  • 1
  • 11
  • 25
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)
Mohit Padalia
  • 1,549
  • 13
  • 10