在Swift中遍历视图控制器层次结构

我想遍历Swift中的视图控制器层次结构,并find一个特定的类。 这里是代码:

extension UIViewController{ func traverseAndFindClass<T : UIViewController>() -> UIViewController?{ var parentController = self.parentViewController as? T? ^ | | // Error: Could not find a user-defined conversion from type 'UIViewController?' to type 'UIViewController' while(parentController != nil){ parentController = parentController!.parentViewController } return parentController } } 

现在,我知道parentViewController属性返回一个可选的UIViewController,但我不知道如何在上帝的名字,我可以使通用一个可选的types。 也许使用某种where子句?

你的方法应该返回T? 而不是UIViewController? ,所以通用types可以从上下文中推断出来。 检查想要的类也要在循环内完成,而不是在循环之前进行一次。

这应该工作:

 extension UIViewController{ func traverseAndFindClass<T : UIViewController>() -> T? { var currentVC = self while let parentVC = currentVC.parentViewController { if let result = parentVC as? T { return result } currentVC = parentVC } return nil } } 

用法示例:

 if let vc = self.traverseAndFindClass() as SpecialViewController? { // .... } 

更新:上述方法不能按预期方式工作(至less不在debuggingconfiguration),我已经把问题作为一个单独的问题: 可选绑定成功,如果不应该 。 一个可能的解决方法(从该问题的答案)似乎是要取代

 if let result = parentVC as? T { ... 

 if let result = parentVC as Any as? T { ... 

或者删除方法定义中的types约束:

 func traverseAndFindClass<T>() -> T? { 

更新2:问题已经被Xcode 7修复,现在traverseAndFindClass()方法正常工作。

而不是循环,我们可以使用recursion(请注意,下面的代码没有被彻底testing):

 // Swift 2.3 public extension UIViewController { public var topViewController: UIViewController { let o = topPresentedViewController return o.childViewControllers.last?.topViewController ?? o } public var topPresentedViewController: UIViewController { return presentedViewController?.topPresentedViewController ?? self } } 

在遍历视图控制器层次结构的更普遍的问题上,一种可能的方法是有两个专用序列,以便我们能够:

 for ancestor in vc.ancestors { //... } 

要么:

 for descendant in vc.descendants { //... } 

哪里:

 public extension UIViewController { public var ancestors: UIViewControllerAncestors { return UIViewControllerAncestors(of: self) } public var descendants: UIViewControllerDescendants { return UIViewControllerDescendants(of: self) } } 

实现祖先序列:

 public struct UIViewControllerAncestors: GeneratorType, SequenceType { private weak var vc: UIViewController? public mutating func next() -> UIViewController? { guard let vc = vc?.parentViewController ?? vc?.presentingViewController else { return nil } self.vc = vc return vc } public init(of vc: UIViewController) { self.vc = vc } } 

实现后代序列:

 public struct UIViewControllerDescendants: GeneratorType, SequenceType { private weak var root: UIViewController? private var index = -1 private var nextDescendant: (() -> UIViewController?)? // TODO: `Descendants?` when Swift allows recursive type definitions public mutating func next() -> UIViewController? { if let vc = nextDescendant?() { return vc } guard let root = root else { return nil } while index < root.childViewControllers.endIndex - 1 { index += 1 let vc = root.childViewControllers[index] var descendants = vc.descendants nextDescendant = { return descendants.next() } return vc } guard let vc = root.presentedViewController where root === vc.presentingViewController else { return nil } self.root = nil var descendants = vc.descendants nextDescendant = { return descendants.next() } return vc } public init(of vc: UIViewController) { root = vc } }