如何识别导航堆栈中的前视图控制器

我有两个独立的 navigationcontrollers,一个与 RootViewControllerA,另一个与 RootViewControllerB。

我可以把 ViewControllerC 推到 A 或 B 的导航栈上。

问题: 当我在 ViewControllerC 中时,如何才能知道我是在属于 A 还是 B 的堆栈中?

97574 次浏览

您可以使用 UINavigationControllerviewControllers属性:

@property(nonatomic, copy) NSArray *viewControllers

讨论: 根视图控制器位于数组中的索引0,后视图控制器位于索引 n-2,顶部控制器位于索引 n-1,其中 n 是数组中的项数。

Https://developer.apple.com/documentation/uikit/uinavigationcontroller

您可以使用它来测试根视图控制器(位于数组索引0处的控制器)是视图控制器 A 还是 B。

使用 navigationController方法检索它。参见 苹果网站上的文档

属于导航的父代或祖先 控制器(只读)

@ property (非原子的,只读的,保留的) UINavigationController * 导航控制器

仅返回导航控制器,如果视图 控制器位于其堆栈中。如果导航 找不到控制器。

可用性 iOS 2.0及更高版本可用。

访问 viewControllers属性的 n-2元素以访问父视图控制器。

一旦有了这个实例,就可以通过记录 NSStringFromClass()函数的结果来检查它的类型。或者可以在控制器 A 和 B 中保留一些 static const标识符字符串,并使用 getter 函数打印出字符串。

以下是公认答案的实现方式:

- (UIViewController *)backViewController
{
NSInteger numberOfViewControllers = self.navigationController.viewControllers.count;


if (numberOfViewControllers < 2)
return nil;
else
return [self.navigationController.viewControllers objectAtIndex:numberOfViewControllers - 2];
}

对公认答案的更普遍的执行:

- (UIViewController *)backViewController {
NSArray * stack = self.navigationController.viewControllers;


for (int i=stack.count-1; i > 0; --i)
if (stack[i] == self)
return stack[i-1];


return nil;
}

这将返回正确的“后视控制器”,而不管当前类在导航堆栈上的什么位置。

- (UIViewController *)backViewController
{
NSInteger myIndex = [self.navigationController.viewControllers indexOfObject:self];


if ( myIndex != 0 && myIndex != NSNotFound ) {
return [self.navigationController.viewControllers objectAtIndex:myIndex-1];
} else {
return nil;
}
}

@ tjklemz 代码的快速实现:

var backViewController : UIViewController? {


var stack = self.navigationController!.viewControllers as Array


for (var i = stack.count-1 ; i > 0; --i) {
if (stack[i] as UIViewController == self) {
return stack[i-1] as? UIViewController
}


}
return nil
}

查找以前的视图控制器很简单。

在你的例子中,也就是说,你在 C 中,你需要 B,[self.navigationController.viewControllers lastObject]就是你想要的。

对于 A,因为 A 是根视图控制器,所以只需用 firstObject替换 lastObject即可获得。

因为死马喜欢挨打:)

- (UIViewController *)previousViewController
{
NSArray *vcStack = self.navigationController.viewControllers;
NSInteger selfIdx = [vcStack indexOfObject:self];
if (vcStack.count < 2 || selfIdx == NSNotFound) { return nil; }
return (UIViewController *)[vcStack objectAtIndex:selfIdx - 1];
}

作为扩展的 Tjklemz代码的快速实现:

extension UIViewController {


func backViewController() -> UIViewController? {
if let stack = self.navigationController?.viewControllers {
for(var i=stack.count-1;i>0;--i) {
if(stack[i] == self) {
return stack[i-1]
}
}
}
return nil
}
}

Swift 2.2的实现-将其添加到 UIViewController扩展中。从某种意义上说,如果 viewcontroller 是 rootvc 或者不在导航控制器中,它将返回 nil

var previousViewController: UIViewController? {
guard let viewControllers = navigationController?.viewControllers else {
return nil
}
var previous: UIViewController?
for vc in viewControllers{
if vc == self {
break
}
previous = vc
}
return previous
}

下面是一个修改过的 普拉布 · 比曼的 Swift 代码版本,它适合支持 Swift 3:

extension UIViewController {
func backViewController() -> UIViewController? {
if let stack = self.navigationController?.viewControllers {
for i in (1..<stack.count).reverse() {
if(stack[i] == self) {
return stack[i-1]
}
}
}
return nil
}
}

斯威夫特还有后卫。

extension UIViewController {


func getPreviousViewController() -> UIViewController? {
guard let _ = self.navigationController else {
return nil
}


guard let viewControllers = self.navigationController?.viewControllers else {
return nil
}


guard viewControllers.count >= 2 else {
return nil
}
return viewControllers[viewControllers.count - 2]
}
}

作为 UINavigationController的扩展:

extension UINavigationController {


func previousViewController() -> UIViewController? {
guard viewControllers.count > 1 else {
return nil
}
return viewControllers[viewControllers.count - 2]
}


}

我的分机,斯威夫特3号

extension UIViewController {
var previousViewController: UIViewController? {
guard let controllers = navigationController?.viewControllers, controllers.count > 1 else { return nil }
switch controllers.count {
case 2: return controllers.first
default: return controllers.dropLast(2).first
}
}
}

对于 Swift 3来说,你可以这样做:

var backtoViewController:UIViewController!
for viewController in (self.navigationController?.viewControllers)!.reversed() {
if viewController is NameOfMyDestinationViewController {
backtoViewController = viewController
}
}
self.navigationController!.popToViewController(backtoViewController, animated: true)

您只需将要返回的“ NameOfMyDestinationViewController”替换为 viewController 即可。

一种更简洁的迅速实现方式:

extension UIViewController {
var previousViewController: UIViewController? {
guard let nav = self.navigationController,
let myIdx = nav.viewControllers.index(of: self) else {
return nil
}
return myIdx == 0 ? nil : nav.viewControllers[myIdx-1]
}
}