如何在导航堆栈中标识以前的视图控制器


78

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

我可以将ViewControllerC推入A或B的导航堆栈中。

问题:当我在ViewControllerC中时,如何确定我是否在属于A或B的堆栈中?


7
为什么不按Push时在C上创建一个previousViewController属性呢?还是在推送时从A或B提供C所需的信息?
特里·威尔科克斯

1
@TerryWilcox,“因为如今的关系可能非常复杂
维亚切斯拉夫

Answers:


107

您可以使用UINavigationControllerviewControllers属性:

@property(nonatomic, copy) NSArray *viewControllers

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

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

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


如何在SWIFT中将其作为字符串获取。(我是
Swift的新手

@cyberboy一样容易:和var viewControllers: [UIViewController]
NerdyTherapist

1
前一个视图控制器将在viewControllers.last
Burak

@BurakviewControllers.last具有当前的视图控制器,为了获得以前的视图控制器,应使用viewControllers[viewControllers.count-2]
Ganpat,

102

这是公认答案的实现:

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

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

20
我建议将此类别添加为UIViewController
MaxGabriel

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

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

11

接受的答案的更一般的实现:

- (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;
}

无论当前类在导航堆栈中的何处,这都将返回正确的“后视图控制器”。


9

快速实现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 3支持,作为新的答案。
Cin316 '16

9

这是Prabhu Beeman的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
    }
}

一些注意事项:reverse()现在是reversed(),并且self.navigationController?.viewControllers永远不会包含“自我”视图控制器,因此返回stack.last应该足够了
Kappe

3

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

拥有该实例后,您可以通过记录该NSStringFromClass()函数的内容来检查其类型。或者,您可以static const在控制器A和B中保留一些标识符字符串,并使用输出该字符串的getter函数。


获取视图控制器当前索引的任何简单方法,还是应根据我的层次结构对它们进行硬编码。
HpTerm

3

作为UINavigationController扩展:

extension UINavigationController {

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

}

2

@tjklemz代码的Swift实现:

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
    }

我怎么能以字符串的形式获取它呢。(我是
Swift的新手

@cyberboy嗨!我不确定我是否理解您的问题。是否要以字符串形式获取backViewController描述?如果是这样,您可以考虑println("backViewController is: \(backViewController.description)"); 这将为您提供类似“ UINavigationController:0x7fcea1d286b0”的描述,该描述不是很清楚,但至少可以识别您的对象。正如我所说,我不确定您到底需要什么...
cdf1982

1

使用navigationController方法进行检索。请参阅Apple网站上的文档

navigationController父级或祖先,它是导航控制器。(只读)

@property(非原子,只读,保留)UINavigationController * navigationController

讨论如果视图控制器在其堆栈中,则仅返回导航控制器。如果找不到导航控制器,则此属性为nil。

可用性在iOS 2.0和更高版本中可用。


1

因为死马喜欢被殴打:)

- (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];
}

1

更简洁的Swift实现:

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]
    }
}

0

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

就您而言,即您在C中并且需要B,[self.navigationController.viewControllers lastObject]这就是您想要的。

对于A,由于A是根视图控制器,因此您只需将其替换lastObjectfirstObject即可。


0

Swift 2.2的实现-在UIViewController扩展中添加它。从某种意义上讲,它是安全的,nil如果viewcontroller是rootvc或不是导航控件中的rootvc ,它将返回。

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
}

0

借助Swift使用后卫。

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]
    }
}

0

我的扩展,迅速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
        }
    }
}

0

对于迅速3,您可以执行以下操作:

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.