【问题标题】:How to get the previous viewcontroller that pushed my current view如何获取推送我当前视图的上一个视图控制器
【发布时间】:2013-05-12 14:12:21
【问题描述】:

我的应用主页有UIButtonsbtnIncomebtnExpense。按下此按钮会分别推动IncomeVCExpenseVC,这是两个UIViewControllersUITabBar 通过xib 添加。 tabBar 有 4 个项目。在每个选项卡项目上选择添加相同的四个视图控制器(其中包含 UITableViews)作为 IncomeVCExpenseVC 的子视图,例如 DailyVC、WeeklyVC、MonthlyVC、YearlyVC。(即,对于收入,有每天,weekly 等,费用也一样)(我这样做是因为IncomeVCExpenseVC 有一个UIButton 和一个UIView,这对于所有选项卡都很常见)。

所以问题是,如果单击btnIncome,我必须使用与收入相关的数组填充这些表格视图,反之亦然。如何从哪个 viewController 中找到我选择了不同的选项卡(我需要从我添加为 IncomeVC 和 ExpenseVC 的子视图的 4 个视图中获取它)。我是否必须为收入和费用分别制作 8 个不同的视图 4? 谢谢。

【问题讨论】:

    标签: iphone uiviewcontroller uinavigationcontroller uitabbarcontroller


    【解决方案1】:

    Swift 3 中,

    if let navController = self.navigationController, navController.viewControllers.count >= 2 {
         let viewController = navController.viewControllers[navController.viewControllers.count - 2]
    }
    

    【讨论】:

      【解决方案2】:

      你可以像下面的代码一样获取之前的viewController,

      NSLog(@"%@",[self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-2]);
      

      这将显示之前的 viewController 名称...

      【讨论】:

      • @Erik 计数属性总是比索引大 1,因此要在当前 UIViewController 之前获取 UIViewController,您必须从计数中减去 2
      • 数组越界可能导致崩溃
      • 我显然知道,这就是我投反对票的原因。您应该修复您的代码或添加评论警告其他人您的代码不安全。顺便说一句,我赞成你回答 Swift 3
      【解决方案3】:

      Swift 中:

      let n: Int! = self.navigationController?.viewControllers?.count
      let myUIViewController = self.navigationController?.viewControllers[n-2] as! UIViewController
      

      【讨论】:

      • 直接n-2访问是不安全的,因为如果你是第一个VC,你会出错。也许您可以使用以前的验证。
      【解决方案4】:

      斯威夫特 3

      这是可以放入扩展的先前答案的混搭:

      extension UIViewController{
         var previousViewController:UIViewController?{
              if let controllersOnNavStack = self.navigationController?.viewControllers, controllersOnNavStack.count >= 2 {
                  let n = controllersOnNavStack.count
                  return controllersOnNavStack[n - 2]
              }
              return nil
          }
      }
      

      编辑:

      在获取给定视图控制器的previousViewController 时,将其称为VC1,在viewWillDisappear 中,VC1 已经从导航控制器堆栈中弹出。所以在这种情况下,上面的代码最终并没有直接获取 VC1 上方的视图控制器(称为 VC2),而是获取 VC2 上方的视图控制器(如果存在)。

      为了避免这个问题,我只在请求previousViewController 时检查VC1 是否仍在堆栈中。这是更新的代码:

      extension UIViewController{
          var previousViewController:UIViewController?{
              if let controllersOnNavStack = self.navigationController?.viewControllers{
                  let n = controllersOnNavStack.count
                  //if self is still on Navigation stack
                  if controllersOnNavStack.last === self, n > 1{
                      return controllersOnNavStack[n - 2]
                  }else if n > 0{
                      return controllersOnNavStack[n - 1]
                  }
              }
              return nil
          }
      }
      

      此代码假定您发送previousViewController 消息的视图控制器将位于导航堆栈的顶部或根本不位于。

      【讨论】:

      • 会不会出现被查看的视图控制器不在导航栈顶部的情况?
      【解决方案5】:

      斯威夫特 5.1 ?

      (基于以前的答案但更简单)

      extension UINavigationController {
          var previousViewController: UIViewController? {
             viewControllers.count > 1 ? viewControllers[viewControllers.count - 2] : nil
          }
      }
      

      【讨论】:

        【解决方案6】:

        如果需要访问前一个视图控制器的原因是要知道要获取什么数据,我建议您在将数据推送到堆栈之前将数据提供给新的视图控制器。或者至少有足够的数据让视图控制器知道如何获取正确的数据,例如枚举或常量或其他东西。

        这可以通过自定义初始化程序或属性来完成。 看看这篇博文的例子:"Passing Data Between View Controllers"

        如果您使用情节提要,可以使用prepareForSegue:sender 传递正确的数据。一个很好的教程可以在这里找到:Beginning Storyboards in iOS 5 Part 2

        【讨论】:

          【解决方案7】:
          UIViewController *previousViewController = [[[self navigationController]viewControllers] objectAtIndex:([viewControllers indexOfObject:self]-1)];
          

          self 将是当前视图控制器。

          【讨论】:

            【解决方案8】:

            斯威夫特

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

            【讨论】:

              【解决方案9】:

              您当然可以重用视图控制器。我建议不要在按下按钮时推送 UIViewController(其中包含从 IB 添加的 UITabBar),而是可以推送包含 4 个视图控制器(每日、每周、每月和每年)的 UITabBarController。

              您的 UITabBarController 可以有一个枚举属性(收入和费用),并且可以在您根据按下的按钮按下此 UITabBarController 时分配它。从那里,您可以将另一个枚举属性(收入和费用)分配给 4 个 UIViewController,以在每个视图控制器中显示正确的数据类型。

              【讨论】:

                【解决方案10】:

                查看这篇文章:How to identify previous view controller in navigation stack Tony 是对的,您可以从 viewControllers 数组中获取之前的 VC,但索引为 n-2。

                【讨论】:

                  【解决方案11】:

                  这里的所有答案都实现了[viewControllers.count - 2] 方法,但它返回最后一个视图控制器的前一个控制器,未声明!如果声明的视图控制器不是最后一个视图导航堆栈的控制器[viewControllers.count - 2] 返回不正确的结果。

                  新解决方案:

                  斯威夫特

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

                  【讨论】:

                    猜你喜欢
                    • 2015-07-23
                    • 1970-01-01
                    • 2010-12-11
                    • 2019-07-03
                    • 2016-07-29
                    • 2011-12-20
                    • 2012-12-02
                    • 2014-03-28
                    • 1970-01-01
                    相关资源
                    最近更新 更多