How can I pop a view from a UINavigationController and replace it with another in one operation?

后端 未结 16 2097
谎友^
谎友^ 2020-11-27 10:01

I have an application where I need to remove one view from the stack of a UINavigationController and replace it with another. The situation is that the first view creates an

相关标签:
16条回答
  • 2020-11-27 10:29

    I've discovered you don't need to manually mess with the viewControllers property at all. Basically there are 2 tricky things about this.

    1. self.navigationController will return nil if self is not currently on the navigation controller's stack. So save it to a local variable before you lose access to it.
    2. You must retain (and properly release) self or the object who owns the method you are in will be deallocated, causing strangeness.

    Once you do that prep, then just pop and push as normal. This code will instantly replace the top controller with another.

    // 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];
    [navController pushViewController:someViewController animated:NO];
    

    In that last line if you change the animated to YES, then the new screen will actually animate in and the controller you just popped will animate out. Looks pretty nice!

    0 讨论(0)
  • 2020-11-27 10:32

    The following approach seems nicer to me, and also works well with ARC:

    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];
    
    0 讨论(0)
  • 2020-11-27 10:32

    I had to do a similar thing recently and based my solution on Michaels answer. In my case I had to remove two View Controllers from the Navigation Stack and then add a new View Controller on. Calling

    [controllers removeLastObject];
    twice, worked fine in my case.

    UINavigationController *navController = self.navigationController;
    
    // retain ourselves so that the controller will still exist once it's popped off
    [[self retain] autorelease];
    
    searchViewController = [[SearchViewController alloc] init];    
    NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
    
    [controllers removeLastObject];
    // In my case I want to go up two, then push one..
    [controllers removeLastObject];
    navController.viewControllers = controllers;
    
    NSLog(@"controllers: %@",controllers);
    controllers = nil;
    
    [navController pushViewController:searchViewController animated: NO];
    

    0 讨论(0)
  • 2020-11-27 10:32

    This UINavigationController instance method might work...

    Pops view controllers until the specified view controller is the top view controller and then updates the display.

    - (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
    
    0 讨论(0)
  • 2020-11-27 10:32

    Here is another approach that doesn't require directly messing with the viewControllers array. Check if the controller has been pop'd yet, if so push it.

    TasksViewController *taskViewController = [[TasksViewController alloc] initWithNibName:nil bundle:nil];
    
    if ([navigationController.viewControllers indexOfObject:taskViewController] == NSNotFound)
    {
        [navigationController pushViewController:taskViewController animated:animated];
    }
    else
    {
        [navigationController popToViewController:taskViewController animated:animated];
    }
    
    0 讨论(0)
  • 2020-11-27 10:34

    Alternatively,

    You can use category to avoid self.navigationController to be nil after popViewControllerAnimated

    just pop and push, it's easy to understand, don't need to access viewControllers....

    // UINavigationController+Helper.h
    @interface UINavigationController (Helper)
    
    - (UIViewController*) popThenPushViewController:(UIViewController *)viewController animated:(BOOL)animated;
    
    @end
    
    
    // UINavigationController+Helper.m
    @implementation UINavigationController (Helper)
    
    - (UIViewController*) popThenPushViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        UIViewController *v =[self popViewControllerAnimated:NO];
    
        [self pushViewController:viewController animated:animated];
    
        return v;
    }
    @end
    

    In your ViewController

    // #import "UINavigationController+Helper.h"
    // invoke in your code
    UIViewController *v= [[MyNewViewController alloc] init];
    
    [self.navigationController popThenPushViewController:v animated:YES];
    
    RELEASE_SAFELY(v);
    
    0 讨论(0)
提交回复
热议问题