这是我发布的Traverse view controller hierarchy in Swift(稍加修改)的可能解决方案:
extension UIViewController {
func traverseAndFindClass<T where T : UIViewController>(T.Type) -> T? {
var currentVC = self
while let parentVC = currentVC.parentViewController {
println("comparing \(parentVC) to \(T.description())")
if let result = parentVC as? T { // (XXX)
return result
}
currentVC = parentVC
}
return nil
}
}
该方法应该遍历父视图控制器层次结构并返回第一个 给定类的实例,如果没有找到则为nil。
但它不起作用,我无法弄清楚原因。可选绑定
标有(XXX)
的内容始终成功,以便返回第一个父视图控制器
即使它不是T
的实例。
可以轻松复制:从“iOS Master-Detail Application”创建项目
Xcode 6 GM中的模板,并将以下代码添加到viewDidLoad()
MasterViewController
课程:
if let vc = self.traverseAndFindClass(UICollectionViewController.self) {
println("found: \(vc)")
} else {
println("not found")
}
self
是MasterViewController
(UITableViewController
的子类)及其
父视图控制器是UINavigationController
。
父视图中没有UICollectionViewController
控制器层次结构,所以我期望这个方法
返回nil
,输出“未找到”。
但这就是发生的事情:
comparing <UINavigationController: 0x7fbc00c4de10> to UICollectionViewController
found: <UINavigationController: 0x7fbc00c4de10>
这显然是错误的,因为UINavigationController
不是它的子类
UICollectionViewController
。也许我犯了一些愚蠢的错误,但我找不到它。
为了隔离问题,我也尝试用自己的类重现它 层次结构,独立于UIKit:
class BaseClass : NSObject {
var parentViewController : BaseClass?
}
class FirstSubClass : BaseClass { }
class SecondSubClass : BaseClass { }
extension BaseClass {
func traverseAndFindClass<T where T : BaseClass>(T.Type) -> T? {
var currentVC = self
while let parentVC = currentVC.parentViewController {
println("comparing \(parentVC) to \(T.description())")
if let result = parentVC as? T { // (XXX)
return result
}
currentVC = parentVC
}
return nil
}
}
let base = BaseClass()
base.parentViewController = FirstSubClass()
if let result = base.traverseAndFindClass(SecondSubClass.self) {
println("found: \(result)")
} else {
println("not found")
}
猜猜是什么?现在它按预期工作!输出是
comparing <MyApp.FirstSubClass: 0x7fff38f78c40> to MyApp.SecondSubClass
not found
更新:
删除泛型方法中的类型约束
func traverseAndFindClass<T>(T.Type) -> T?
@POB在评论中建议使其按预期工作。
通过“两步绑定”替换可选绑定
if let result = parentVC as Any as? T { // (XXX)
@vacawama在他的回答中提出的建议也使它按预期工作。 最后一点可能表明这是一个Swift编译器或运行时错误。我还是
无法理解为什么问题出现在UIViewController
的子类中,但不是
使用我的BaseClass
的子类。因此,我将把问题保持开放
在接受答案之前。
更新2 :自 Xcode 7 起修复此问题。
使用最终的Xcode 7
释放问题不再发生。可选绑定
if let result = parentVC as? T
方法中的traverseAndFindClass()
现在可以在Release和Debug配置中按预期工作(和失败)。
答案 0 :(得分:3)
如果您尝试将类型为UINavigationController
的对象有条件地投射到游乐场中的UICollectionViewController
:
var nc = UINavigationController()
if let vc = nc as? UICollectionViewController {
println("Yes")
} else {
println("No")
}
您收到此错误:
Playground执行失败:: 33:16:错误:'UICollectionViewController'不是'UINavigationController'的子类型 如果让vc = nc为? UICollectionViewController {
但如果你改为:
var nc = UINavigationController()
if let vc = (nc as Any) as? UICollectionViewController {
println("Yes")
} else {
println("No")
}
打印“否”。
所以我建议尝试:
extension UIViewController {
func traverseAndFindClass<T where T : UIViewController>(T.Type) -> T? {
var currentVC = self
while let parentVC = currentVC.parentViewController {
println("comparing \(parentVC) to \(T.description())")
if let result = (parentVC as Any) as? T { // (XXX)
return result
}
currentVC = parentVC
}
return nil
}
}