如何弹出已推送的视图控制器下面的视图控制器?

10

我想将一个视图控制器推入堆栈,然后弹出推入新视图控制器的第一个视图控制器。

-(void) someMethod {
    MegaSuperAwesomeViewController *tempVC = [[MegaSuperAwesomeViewController alloc] init];
    [self.navigationController pushViewController:tempVC animated:YES];
    [tempVC release];

    // pop this VC, how?
}

编辑:事实证明,一旦完成新视图控制器,我可以弹出2个视图控制器。 还不是我想要的完全,但它可行。 缺点是我需要设置一个标志来指示覆盖的视图已完成。


你为什么想要这样做? - Mads Mobæk
应用程序的要求。或者我可以弹出当前视图控制器,然后推入下一个视图控制器,但在完成推入之前,当前视图控制器将被释放。 - TigerCoding
5个回答

16

以下是一种弹出两个视图控制器的技巧,该技巧与您面临的问题类似:在第一次弹出后,当前视图控制器和其navigationController属性会立即消失:

以下是一种弹出两个视图控制器的技巧,该技巧与您面临的问题类似:在第一次弹出后,当前视图控制器和其navigationController属性会立即消失:

// pop back 2 controllers on the stack to the setup screen
//

// 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 back 2 controllers to the setup screen
//
[navController popViewControllerAnimated:NO];
[navController popViewControllerAnimated:YES];

或者,您可以直接在视图控制器的导航控制器堆栈上“完成”操作:

setViewControllers:animated: 使用指定的项目替换由导航控制器当前管理的视图控制器。

  • (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated 参数 viewControllers 要放置在堆栈中的视图控制器。此数组中控制器的从前到后顺序表示导航堆栈中从底部到顶部的新顺序。因此,添加到数组中的最后一个项目成为导航堆栈的顶部项目。 animated 如果为YES,则对顶部视图控制器进行推送或弹出动画。如果为NO,则替换视图控制器而不进行任何动画。 讨论 您可以使用此方法在不显式推送或弹出每个控制器的情况下更新或替换当前的视图控制器堆栈。此外,此方法使您能够在不动画更改的情况下更新控制器集,这可能是适当的启动时,在该时刻您希望将导航控制器返回到先前状态。

如果启用了动画效果,则此方法会基于items数组中的最后一个项目是否已经在导航堆栈中决定执行哪种类型的转换。如果视图控制器当前在堆栈中,但不是最高项目,则此方法使用弹出转换。如果它是最高项目,则不执行转换。如果视图控制器不在堆栈中,则此方法使用推送转换。只执行一次转换,但当该转换完成时,整个堆栈的内容都将被替换为新的视图控制器。例如,如果控制器A、B和C在堆栈上,并且您设置了控制器D、A和B,则此方法使用弹出转换,结果堆栈包含控制器D、A和B。

可用性iOS 3.0及更高版本声明于UINavigationController.h

因此,在您的视图控制器的viewDidLoad方法中,“消失”导航堆栈上的下一个视图控制器,您可以这样做:

NSMutableArray *VCs = [self.navigationController.viewControllers mutableCopy];
[VCs removeObjectAtIndex:[VCs count] - 2];
self.navigationController.viewControllers = VCs;

感谢您的尝试,但是导航数组与您描述的VCs数组不兼容,因为它必须是可变的。然而,它并不是真正需要的,因为我可以在完成后从新的VC中弹出两个VC。不知道为什么我没有注意到它。 - TigerCoding
刚刚在编辑中添加了一个“Mutable”——小错误,但技术还是有效的。 - Bogatyr
它不兼容,所以我想我必须创建一个新数组,删除vc,然后再放回数组?我想知道那样会不会引起问题... - TigerCoding
好的。我没有在实际构建中验证代码,但你已经有了想法:获取viewControllers数组,编辑它,并将其设置回去。没有问题,API特别允许您设置一个新的视图控制器数组,请参见我的答案中的“setViewControllers”。 - Bogatyr

8

我也曾经困惑过这个问题,所以我想分享一下我是如何解决的。

假设你有一个VC栈,VC1 是根视图控制器,然后你推入了 VC2,接着从 VC2 推入了 VC3,但是一旦推入 VC3,你不希望用户回到 VC2,而是回到 VC1(根视图控制器)。实现方法如下:

//push VC3 from VC2
[[self navigationController] pushViewController:VC3 animated:YES];

// now remove VC2 from the view controllers array so we will jump straight back to VC1
NSMutableArray *viewHeirarchy =[[NSMutableArray alloc] initWithArray:[self.navigationController viewControllers]];
[viewHeirarchy removeObject:self];
self.navigationController.viewControllers = viewHeirarchy;

希望这能帮助到其他人。

1
其他方法会让旧的视图控制器导航项留在堆栈中。这是唯一一个在iOS 7引入popGestures后对我正常工作的方法。谢谢! - chourobin
太好了,这对我也起作用了。最初我尝试在VC2推送VC3之后(在UINavigationController的委托方法中)执行此操作,这在iOS8中有效,但在iOS7中需要直接推送才能使导航项正确弹出。这也意味着更简单的代码! - Rajveer

0

感谢Bogatyr提供的关于“在navcontroller的viewcontroller数组上进行派对”的提示。我刚刚用我想要更改的一个viewcontroller替换了整个堆栈,然后记录下堆栈中的所有viewcontroller,以确保它是唯一的!效果很好 - 谢谢!

    RatingsTableViewController *newViewController = [[RatingsTableViewController alloc] init];
    NSMutableArray * newVCarray = [NSMutableArray arrayWithObjects:newViewController, nil];
    self.navigationController.viewControllers = newVCarray;

    [newViewController release];

     NSMutableArray *allControllers = [[NSMutableArray alloc] initWithArray:self.navigationController.viewControllers];

    for (id object in allControllers) {

          NSLog(@"name VC: %@", object);
    }
    [allControllers release];

0
-(void)popToSelf{

    NSArray *array = [self.navigationController viewControllers];

    for (int i = 0 ; i < array.count ; i++) {
        UIViewController *currentVC = [array objectAtIndex:i];
        if ([currentVC isKindOfClass:[YourViewControllerClass class]]) {
            [self.navigationController popToViewController:[array objectAtIndex:i] animated:YES];
        }
    }
}

0

最近我使用以下代码在Swift中完成了这个。

private func removePushedLoadingViewFromNavHeirarchy() {
    let viewHeirarchyWithoutLoadingView = rootNavigationController
        .viewControllers
        .filter { $0 as? FullScreenLoadingViewController == nil }
    rootNavigationController.viewControllers = viewHeirarchyWithoutLoadingView
}

在推送另一个视图控制器后,我这样调用它

let viewController = ReviewViewController()
rootNavigationController.pushViewController(viewController, animated: true)
removePushedLoadingViewFromNavHeirarchy()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接