您需要将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(...) 识别子类实例:OK
在以下示例中,两个子类实例被正确识别,并将它们的引用返回给调用者。
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 对象(在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的子类,上述方法就可以使用;而如果您尝试搜索超类对象,您将在UINavigationController.viewControllers 中获得第一个控制器。
关于 edelaney05:s 下面 cmets 中的相关问题的补充
如果评论被删除,我将首先引用问题:
edelaney05:有没有办法防止这种情况发生?这是一个非常有趣的边缘案例,特别是如果你有一个
中级。 class FooVC: AwesomeVC { ... }、class BarVC: AwesomeVC { ... } 和 class AwesomeVC: UIViewController { ... }。
是的,您可以解决此问题,以防您知道您将使用 UIViewController 的纯(1 级)子类以外的其他子类;比如说,允许找到第一个实例
-
UIViewController 的子类。 (+)
- 这些子类的子类。 (++)
我们可以利用动态类型比较来确保我们不会将子类实例转换为其超类(从而将子类实例错误地识别为我们正在寻找的超类实例)。
extension UINavigationController {
func fhkFindFirst<T: UIViewController>(_: T.Type) -> T? {
for viewController in viewControllers {
if let supClassType = viewController.superclass?.dynamicType where supClassType != T.Type.self {
if let viewController = viewController as? T {
return viewController
}
}
}
return nil
}
}
class FooBarViewController: UIViewController { }
class FooViewController : FooBarViewController { }
class BarViewController : FooBarViewController { }
let fooBarViewController = FooBarViewController()
let fooViewController = FooViewController()
let barViewController = BarViewController()
let navController = UINavigationController(rootViewController: fooViewController)
navController.addChildViewController(barViewController)
navController.addChildViewController(fooBarViewController)
print(navController.fhkFindFirst(FooViewController) ?? "None found.")
/* <__lldb_expr_1582.FooViewController: 0x7fe22a712e40> */
print(navController.fhkFindFirst(BarViewController) ?? "None found.")
/* <__lldb_expr_1582.BarViewController: 0x7fe22a4196a0> */
print(navController.fhkFindFirst(FooBarViewController) ?? "None found.")
/* <__lldb_expr_1582.FooBarViewController: 0x7fe22a70ee60> */