Mar*_*n R 9 generics ios swift
这是我在Swift中发布的Traverse视图控制器层次结构的可能解决方案(稍加修改):
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
}
}
Run Code Online (Sandbox Code Playgroud)
该方法应遍历父视图控制器层次结构并返回给定类的第一个实例,如果没有找到则返回nil.
但它不起作用,我无法弄清楚原因.标记为的可选绑定(XXX) 始终成功,因此即使第一个父视图控制器不是实例,也会返回第一个父视图控制器T.
这很容易重现:从Xcode 6 GM中的"iOS Master-Detail Application"模板创建项目,并viewDidLoad()在
MasterViewController类中添加以下代码:
if let vc = self.traverseAndFindClass(UICollectionViewController.self) {
println("found: \(vc)")
} else {
println("not found")
}
Run Code Online (Sandbox Code Playgroud)
self是MasterViewController(的子类UITableViewController),其父视图控制器是UINavigationController.有没有UICollectionViewController在父视图控制器层次,所以我希望该方法返回nil,并输出"未找到".
但这是发生的事情:
comparing <UINavigationController: 0x7fbc00c4de10> to UICollectionViewController
found: <UINavigationController: 0x7fbc00c4de10>
Run Code Online (Sandbox Code Playgroud)
这显然是错误的,因为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")
}
Run Code Online (Sandbox Code Playgroud)
你猜怎么着?现在它按预期工作!输出是
comparing <MyApp.FirstSubClass: 0x7fff38f78c40> to MyApp.SecondSubClass
not found
Run Code Online (Sandbox Code Playgroud)
更新:
删除泛型方法中的类型约束
func traverseAndFindClass<T>(T.Type) -> T?
Run Code Online (Sandbox Code Playgroud)
正如@POB在评论中所建议的那样,它可以按预期工作.
通过"两步绑定"替换可选绑定
if let result = parentVC as Any as? T { // (XXX)
Run Code Online (Sandbox Code Playgroud)
正如@vacawama在他的回答中所建议的那样,它也能按预期工作.
最后一点可能表明这是一个Swift编译器或运行时错误.我仍然无法看到为什么问题出现在子类中UIViewController,而不是我的子类BaseClass.因此,在接受答案之前,我会将问题保持开放一段时间.
更新2:从Xcode 7开始修复此问题.
随着最终的Xcode 7发布,问题不再发生.现在if let result = parentVC as? T,traverseAndFindClass()方法中的可选绑定
在Release和Debug配置中按预期工作(并且失败).
如果您尝试有条件地将Playground 中的类型对象强制转换UINavigationController为 a :UICollectionViewController
var nc = UINavigationController()
if let vc = nc as? UICollectionViewController {
println("Yes")
} else {
println("No")
}
Run Code Online (Sandbox Code Playgroud)
你会得到这个错误:
Playground 执行失败::33:16:错误:如果让 vc = nc as,“UICollectionViewController”不是“UINavigationController”的子类型?UICollectionViewController {
但如果你这样做:
var nc = UINavigationController()
if let vc = (nc as Any) as? UICollectionViewController {
println("Yes")
} else {
println("No")
}
Run Code Online (Sandbox Code Playgroud)
它打印“否”。
所以我建议尝试:
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
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
559 次 |
| 最近记录: |