我在Xcode 8.3.3中使用Swift 3.
我有2个视图控制器,A
和B
,它们从常规UIViewController
继承,如下所示:
class A: UIViewController {}
class B: UIViewController {}
这两个视图控制器可以由UINavigationController
中的基本视图控制器显示。
我有一个不同的视图控制器Test
,它最终将由A
或B
呈现,这意味着在层次结尾的某处,如下所示:
Base
- > A
或B
- > Other
- > Other
- > Test
Test
会根据它来自哪个来呈现不同的数据。
我在UIViewController
上有一个扩展程序,它提供了一种检查方式,当我为A
和B
进行硬编码时,它的工作正常:
extension UIViewController {
var isFromA: Bool {
if let nc = parent as? UINavigationController {
return nc.viewControllers.filter({ ($0 as? A) != nil }).count > 0
} else {
if let _ = parent as? A {
return true
} else if parent != nil {
return parent!.isFromA
} else {
return false
}
}
}
var isFromB: Bool {
if let nc = parent as? UINavigationController {
return nc.viewControllers.filter({ ($0 as? B) != nil }).count > 0
} else {
if let _ = parent as? B {
return true
} else if parent != nil {
return parent!.isFromB
} else {
return false
}
}
}
}
在Test
生命周期代码中,我可以像这样使用它:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if isFromA {
// do something
} else if isFromB {
// do something else
}
}
所以现在我要添加一个新的视图控制器C
,它最终也会显示Test
。我不想在制作isFromC
var时再次复制和粘贴代码。我想创建一个辅助函数,它接受一类类的实例在这些as?
检查中使用。新代码看起来像这样:
extension UIViewController {
var isFromA: Bool {
return isFrom(A)
}
var isFromB: Bool {
return isFrom(B)
}
var isFromC: Bool {
return isFrom(C)
}
fileprivate func isFrom(_ viewControllerClass: UIViewController) -> Bool {
if let nc = parent as? UINavigationController {
return nc.viewControllers.filter({ ($0 as? viewControllerClass) != nil }).count > 0
} else {
if let _ = parent as? viewControllerClass {
return true
} else if parent != nil {
return parent!.isFrom(viewControllerClass)
} else {
return false
}
}
}
}
这不能编译,反正它也不太正确,因为我没有实际的A
,B
或C
实例传递给这个辅助函数
那么解决这个问题的最佳方法是什么?另请注意,我也很乐意提供有关重新设计辅助功能代码的建议,因为我不确定它是否涵盖导航控制器的所有组合等。
答案 0 :(得分:0)
在找到一些搜索之后,我想出了一种将类型作为参数传递的方法。但我看到的例子没有具体涵盖我的上下文(检测当前呈现的视图控制器是否在某种程度上是另一种类型的视图控制器的下游),所以我决定提出问题,并提供我自己的答案。不过,我仍然对帮助函数的任何更改感兴趣。
但这是我的解决方案:
extension UIViewController {
var isFromA: Bool {
return isFrom(viewControllerClassType: A.self)
}
var isFromB: Bool {
return isFrom(viewControllerClassType: B.self)
}
var isFromC: Bool {
return isFrom(viewControllerClassType: C.self)
}
fileprivate func isFrom(viewControllerClassType type: UIViewController.Type) -> Bool {
if let nc = parent as? UINavigationController {
return nc.viewControllers.filter({ $0.isKind(of: type) }).count > 0
} else {
if let _ = parent?.isKind(of: type) {
return true
} else if parent != nil {
return parent!.isFrom(viewControllerClassType: type)
} else {
return false
}
}
}
}
我不知道使用UIViewController.Type
是否是最好的方法,但它确实能够胜任。
答案 1 :(得分:0)
您可以修改一下您在函数中使用泛型类型的内容并调用它而不是计算出的变量。
extension UIViewController {
func isFrom<T>(viewControllerClass: T) -> Bool {
guard let parent = parent else { return false }
if let nav = parent as? UINavigationController {
return nav.viewControllers.filter({ type(of: $0).self is T }).count > 0
} else {
if parent is T {
return true
} else {
return parent.isFrom(viewControllerClass: viewControllerClass)
}
}
}
}
然后用
调用它if vc.isFrom(viewControllerClass: ClassA.self) {
// do something
} else if vc.isFrom(viewControllerClass: ClassB.self) {
// do something
}
这至少消除了为每个父类类型添加新var的需要。