【问题标题】:How to find the calling viewController in my stack?如何在我的堆栈中找到调用 viewController?
【发布时间】:2020-05-29 18:58:07
【问题描述】:

我有一个应用程序,其中包含两个故事板、一个标签栏控制器和 6 个以上嵌入在它们自己的导航控制器中的视图控制器。

我从所有 VC 中的 barButtonItem 模态地呈现 CartViewController,并从 tableViewCell 中呈现 CustomersVC。我的问题是,当我从购物车中展示客户时,我可以再次从 CustomersVC 转到购物车,然后继续循环......

假设

我的假设是,如果我从 anyVC 模态显示 Cart,然后从 cart 模态显示一个 navigationController,然后再显示 CustomersVC,这样的数组就会存在:

  1. 任何视图控制器
  2. CartViewController
  3. CustomersNavigationController
  4. 客户视图控制器

为了解决这个问题,我正在尝试从 customersVC 中删除“ViewCart”barButtonItem,如果它是从购物车中调用的。我的问题是我无法遍历堆栈来检查它。我已经尝试了在 SO 找到的几种方法,但都没有。

我知道我可以使用委托并设置变量来显示/隐藏按钮,但我渴望学习并且希望它更强大,而不必记住手动设置和重置 var。

有什么建议吗?

代码


extension UIViewController {
    @objc func viewCart() {
        if Cart.sharedInstance.order.items.count != 0 {

            let storyboard = UIStoryboard(name: "Cart", bundle: nil)
            if let cartVC = storyboard.instantiateViewController(withIdentifier: "Cart") as? CartViewController {
                let cartNavigationController = UINavigationController(rootViewController: cartVC)
                self.present(cartNavigationController, animated: true)
            }
        }
    }
}

Class CartViewController {

  let storyboard = UIStoryboard(name: "Main", bundle: nil)
   if let customersNC = storyboard.instantiateViewController(withIdentifier: "CustomersNC") as? UINavigationController {
   present(customersNC, animated: true)

}


class CustomersTableViewController {

override func viewDidLoad() {

// Tried presentingViewController:

    if let CartVC = presentingViewController as? CartViewController {
        myButton.isEnabled = false
    }

// Tried navigationController?.viewControllers:

        guard let controllersInStack = navigationController?.viewControllers else { return }
        if let CartVC controllersInStack.first(where: { $0 is CartViewController }) as? CartViewController  {
            myButton.isEnabled = false
        }

// Tried an extension I found here https://stackoverflow.com/questions/38583941/get-all-list-of-uiviewcontrollers-in-ios-swift, but it returns nil

extension UIViewController {
   /**
    * Traverses the entire VC hirearchy downwards and collects VC'w that are of speccific PARAM: type
    * - Fixme: ⚠️️ this can be written more elegantly with flatMap
    * ## Example:
    * let vc: CustomVC? = UIApplication.shared.delegate?.window?.rootViewController?.descendants().first
    */
   func descendants<T>(type: T.Type? = nil) -> [T] {
       var childrenOfType: [T] = []
       self.children.forEach {
           if let child: T = ($0 as? T) {
               childrenOfType.append(child)
           }
           if !$0.children.isEmpty {
               childrenOfType += $0.descendants(type: type)
           }
       }
       return childrenOfType
   }
}

【问题讨论】:

  • 没有这样的数组,所以你的假设是错误的。与其做出错误的假设,不如专注于问题的现实。从您目前所说的来看,听起来只要问一下是否有navigationController 就足够了。但是,如果您能画出更好的情况图,即显示 整个 视图控制器层次结构,当您希望能够说“ go no deep”,每一步都提供完整信息,说明我们为到达这里所做的工作(孩子、推送或礼物)。

标签: ios swift xcode


【解决方案1】:

每个视图控制器都有一个parentpresentingViewController(或两者都有),因此通过询问这些,您可以找出“你在哪里”。

这通常足以告诉您情况,特别是如果您明智地使用类类型(例如,您可以将导航控制器设置为不同的 UINavigationController 子类,只是为了知道您以后在哪里)。

如果你想要一个完整的视图控制器链到你所在的位置,你可以递归地沿着链向上追踪,像这样:

func trace(_ vc: UIViewController) {
    print(vc)
    if let parent = vc.parent {
        print("parent:")
        trace(parent)
        return
    }
    if let presenter = vc.presentingViewController {
        print("presenter:")
        trace(presenter)
        return
    }
    print("done")
}

该示例打印而不是累积视图控制器列表以及每个视图控制器之间的连接性质(这是您真正需要的),但是通过从链中的“最后一个”视图控制器调用它,您在您想说“不要再深入”的时候,您可以在脑海中大致了解链条的样子。

这是一个更完整的示例,展示了如何将反向跟踪累积到数组中:

class MyVC: UIViewController {
    func makeTrace() {
        super.viewDidAppear(animated)
        let result = self.trace([(.start, self)])
        print(result)
    }
    enum Link: String {
        case parent
        case presenter
        case start
    }
    typealias Chain = [(Link, UIViewController)]
    func trace(_ chain: Chain) -> Chain {
        if let parent = chain.last!.1.parent {
            return trace(chain + [(.parent, parent)])
        }
        if let presenter = chain.last!.1.presentingViewController {
            return trace(chain + [(.presenter, presenter)])
        }
        return chain
    }
}

所以result 会告诉你足够多的信息来知道“你在哪里”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-14
    • 2014-08-05
    • 1970-01-01
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 2018-03-20
    • 1970-01-01
    相关资源
    最近更新 更多