gpt4 book ai didi

ios - Swift 泛型 : function with T. 类型作为参数返回可选 T

转载 作者:搜寻专家 更新时间:2023-10-30 22:12:54 29 4
gpt4 key购买 nike

我正在尝试编写一系列通用函数,这些函数将通过传递 UIViewController 类或子类 Type 对一堆 viewController 进行排序,然后返回“找到的”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 不是类型。

我不太确定我在这里遗漏了什么......

最佳答案

您需要将 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

但是请注意,从子类类型到其父类(super class)的尝试转换总是会成功,因此上面的解决方案将正确识别子类实例(UIViewController 的子类),而如果您查询父类(super class)实例(即 T 作为父类(super class) 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(...) 查找父类(super class)实例:不符合预期

而在下面的例子中,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 的子类,上面的方法就可以工作;而如果您尝试搜索父类(super class)对象,您将在 UINavigationController.viewControllers 中获得第一个 Controller 。


在下面的评论中添加关于 edelaney05:s 的相关问题

我将首先引用问题以防评论被删除:

edelaney05: Is there a way to guard against this? This is a pretty interesting edge case to consider especially if you've got an intermediate class. class FooVC: AwesomeVC { ... }, class BarVC: AwesomeVC { ... }, and class AwesomeVC: UIViewController { ... }.

是的,您可以解决此问题,以防您知道您将使用的不仅仅是 UIViewController 的纯(第一级)子类;比如说,允许找到第一个实例

  • UIViewController 的子类。 (+)
  • 这些子类的子类。 (++)

我们可以使用动态类型比较来确保我们不会将子类实例转换为其父类(super class)(因此将子类实例错误地识别为我们正在寻找的父类(super class)实例)。

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> */

关于ios - Swift 泛型 : function with T. 类型作为参数返回可选 T,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35089223/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com