我尝试编写一系列通用函数,它们通过传递UIViewController
类或子类Type来对一堆viewControllers进行排序,然后返回"找到的实例&# 34; viewController或者没有。到目前为止,我甚至无法编写这个简单的代码片段:
extension UINavigationController {
func fhk_find<T: UIViewController>(viewControllerType: T.Type) -> T?
{
if let viewController = viewControllers.first as? viewControllerType {
return viewController
}
else {
return nil
}
}
}
并打电话:
navController.fhk_find(fooViewController.self)
但是,编译器告诉我viewControllerType
不是类型。
我不确定我在这里失踪的是什么......
答案 0 :(得分:5)
您需要将viewControllers.first
(如果存在)转换为T
,而不是参数viewControllerType
。事实上,你根本不需要使用这个参数;您可以将扩展名修改为以下内容:
extension UINavigationController {
func fhkFindFirst<T: UIViewController>(_: T.Type) -> T? {
for viewController in viewControllers {
if let viewController = viewController as? T {
return viewController
}
}
return nil
}
}
示例用法如下。请注意,您使用fooViewController.dynamicType
而非fooViewController.self
进行了通话。后者为您提供fooViewController.self
的值而不是类型,即fooViewController.self = fooViewController.self
。
现在请注意,尝试从子类类型到其超类的转换将始终成功,因此上面的解决方案将正确识别子类实例(UIViewController
的子类),而如果查询超类实例(即,T
作为超类UIViewController
),即使viewController = viewController as? T
实际上是viewController
的子类的实例,UIViewController
也会成功。
使用fhkFindFirst(...)
标识子类实例:确定
在以下示例中,正确标识了两个子类实例,并将其引用返回给调用者。
class FooViewController : UIViewController { }
class BarViewController : UIViewController { }
let fooViewController = FooViewController()
let barViewController = BarViewController()
let navController = UINavigationController(rootViewController: fooViewController)
navController.addChildViewController(barViewController)
print(navController.fhkFindFirst(fooViewController.dynamicType) ?? "None found.")
// or: print(navController.fhkFindFirst(FooViewController))
/* <__lldb_expr_1582.FooViewController: 0x7fb97840ad80> */
print(navController.fhkFindFirst(barViewController.dynamicType) ?? "None found.")
// or: print(navController.fhkFindFirst(BarViewController))
/* <__lldb_expr_1582.BarViewController: 0x7fb978709340> */
使用fhkFindFirst(...)
查找超类实例:不按预期
在以下情况中,fooViewController
是一个UIViewController
对象,并且被错误标识为BarViewController
,因为BarViewController
对象的类型转换(在{ {1}})UINavigationController.viewControllers
成功。
UIViewController
总结;只要您只使用该方法搜索class BarViewController : UIViewController { }
let fooViewController = UIViewController()
let barViewController = BarViewController()
let navController = UINavigationController(rootViewController: barViewController)
navController.addChildViewController(fooViewController)
print(navController.fhkFindFirst(fooViewController.dynamicType) ?? "None found.")
// or: print(navController.fhkFindFirst(UIViewController))
/* <__lldb_expr_1533.BarViewController: 0x7fa519e2bd40> <-- "wrong" one */
print(navController.fhkFindFirst(barViewController.dynamicType) ?? "None found.")
// or: print(navController.fhkFindFirst(BarViewController))
/* <__lldb_expr_1533.BarViewController: 0x7fa519e2bd40> */
的子类,上述操作就会起作用;而如果你试图搜索一个超类对象,你将获得UIViewController
中的第一个控制器。
关于edelaney05:以下评论中的相关问题的补充
我首先引用问题,以防删除评论:
edelaney05:有没有办法防范这个?这是一个非常有趣的边缘案例,特别是如果你有一个 中级班。
UINavigationController.viewControllers
,class FooVC: AwesomeVC { ... }
和class BarVC: AwesomeVC { ... }
。
是,您可以解决此问题,以防您知道自己将使用class AwesomeVC: UIViewController { ... }
的纯(第一级)子类以外的其他工作;比如,允许找到
UIViewController
的子类。 (+)我们可以利用动态类型比较来确保我们不执行子类实例到其超类的转换(因此错误地将子类实例标识为我们正在寻找的超类实例)。
UIViewController