Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift泛型:参数为T.Type的函数返回可选的T_Ios_Swift_Generics - Fatal编程技术网

Ios Swift泛型:参数为T.Type的函数返回可选的T

Ios Swift泛型:参数为T.Type的函数返回可选的T,ios,swift,generics,Ios,Swift,Generics,我试图编写一系列通用函数,通过传递UIViewController类或子类类型,然后返回“found”viewController的实例或nil,对viewController堆栈进行排序。到目前为止,我甚至无法编译这个简单的代码片段: extension UINavigationController { func fhk_find<T: UIViewController>(viewControllerType: T.Type) -> T? {

我试图编写一系列通用函数,通过传递
UIViewController
类或子类类型,然后返回“found”viewController的实例或nil,对viewController堆栈进行排序。到目前为止,我甚至无法编译这个简单的代码片段:

extension UINavigationController {

    func fhk_find<T: UIViewController>(viewControllerType: T.Type) -> T?
    {
        if let viewController = viewControllers.first as? viewControllerType {
            return viewController
        }
        else {
            return nil
        }
    }
}
但是,编译器告诉我,
viewControllerType
不是一个类型


我不太确定这里缺少了什么…

您需要将
视图控制器强制转换。首先
(如果存在)转换为
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
    }
}

使用
fhkFindFirst(…)
查找超类实例:不符合预期

而在以下情况下,
fooViewController
是一个
UIViewController
对象,并且被错误地识别为
BarViewController
,因为
BarViewController
对象(在
UINavigationController.viewControllers
中)的类型转换成功

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

啊!!我知道这很简单。非常感谢。谢谢你指出“自我vs.动态类型”让我避免了将来的头疼。@StephenNewton很乐意帮忙。还请注意,我更新了扩展方法,使其遵循Swift
camelCase
方法名称命名约定。@StephenNewton注意我的编辑:只要只搜索
UIViewController
的子类实例,上述解决方案就可以正常工作,但如果尝试搜索超类对象(
UIViewController
),则将始终在
UINavigationController.viewControllers
中返回第一个实例。但是,这应该是可以的,因为您所有的ViewController都应该是
UIViewController
@dfri的子类的实例,有什么方法可以防止这种情况发生吗?这是一个非常有趣的边缘案例,特别是如果你有中间类的话。代码>类FooVC:AwesomeVC{…}
类BarVC:AwesomeVC{…}
,和
类AwesomeVC:UIViewController{…}
@edelaney05是的,我们可以解决这个问题;见上面编辑的答案。
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> */
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> */
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> */