【问题标题】:How to identify previous view controller in navigation stack如何识别导航堆栈中的前一个视图控制器
【发布时间】:2011-10-23 18:18:42
【问题描述】:

我有两个单独的navigationcontrollers,一个是RootViewController A,另一个是RootViewController B。

我可以将ViewController C 推送到 A 或 B 的导航堆栈中。

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

【问题讨论】:

  • 为什么不直接在 C 上创建一个 previousViewController 属性,在推送 C 时设置它?还是在推送时从 A 或 B 向 C 提供所需的信息?
  • @TerryWilcox ,'因为现在的关系可能非常复杂

标签: objective-c ios uiviewcontroller uinavigationcontroller


【解决方案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]
    }
}

【讨论】:

    【解决方案2】:

    您可以使用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]
    • 上一个视图控制器将位于viewControllers.last
    • @Burak viewControllers.last 有当前的视图控制器,为了获得以前的视图控制器,应该使用viewControllers[viewControllers.count-2]
    【解决方案3】:

    对于 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。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        作为UINavigationController 扩展:

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            这是Prabhu Beeman's 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 永远不会包含“self”视图控制器,所以 return stack.last 应该足够了
            【解决方案8】:

            Swift 2.2 的实现 - 将此添加到 UIViewController 扩展中。从某种意义上说是安全的,如果视图控制器是 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
            }
            

            【讨论】:

              【解决方案9】:

              tjklemz 代码作为扩展的 Swift 实现:

              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。
              【解决方案10】:

              因为死马喜欢被打:)

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

              【讨论】:

                【解决方案11】:

                查找前一个视图控制器很简单。

                在您的情况下,即您在 C 中并且您需要 B,[self.navigationController.viewControllers lastObject] 就是您想要的。

                对于A来说,由于A是根视图控制器,只需将lastObject替换为firstObject即可获得。

                【讨论】:

                  【解决方案12】:

                  @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”的描述,不是很清楚,但至少可以让你识别对象。正如我所说,我不确定你到底需要什么......
                  【解决方案13】:
                  - (UIViewController *)backViewController
                  {
                      NSInteger myIndex = [self.navigationController.viewControllers indexOfObject:self];
                  
                      if ( myIndex != 0 && myIndex != NSNotFound ) {
                          return [self.navigationController.viewControllers objectAtIndex:myIndex-1];
                      } else {
                          return nil;
                      }
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    已接受答案的更通用实现:

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

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

                    【讨论】:

                      【解决方案15】:

                      这是接受的答案的实现:

                      - (UIViewController *)backViewController
                      {
                          NSInteger numberOfViewControllers = self.navigationController.viewControllers.count;
                      
                          if (numberOfViewControllers < 2)
                              return nil;
                          else
                              return [self.navigationController.viewControllers objectAtIndex:numberOfViewControllers - 2];
                      }
                      

                      【讨论】:

                      • 我建议将此作为类别添加到UIViewController
                      【解决方案16】:

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

                      获得该实例后,您可以通过记录NSStringFromClass() 函数的结果来检查其类型。或者,您可以在控制器 A 和 B 中保留一些 static const 标识符字符串,以及打印出字符串的 getter 函数。

                      【讨论】:

                      • 获取视图控制器当前索引的任何简单方法,或者我应该根据我的层次结构对它们进行硬编码。
                      【解决方案17】:

                      使用navigationController 方法检索它。见documentation on Apple's site

                      navigationController 作为导航的父级或祖先 控制器。 (只读)

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

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

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

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2023-03-08
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2015-05-17
                        • 1970-01-01
                        • 1970-01-01
                        • 2012-05-04
                        相关资源
                        最近更新 更多