为什么我需要使用此Swift泛型函数强制类型?

时间:2016-12-08 20:00:37

标签: swift generics

我有一些重复的UIViewController样板分散在我想要封装的周围,所以我定义了这个通用的UIViewController扩展方法:

extension UIViewController {
    func instantiateChildViewController<T: UIViewController>(
        storyboardName: String? = nil,
        identifier: String? = nil
    ) -> T {
        let storyboard: UIStoryboard!
        if let name = storyboardName {
            storyboard = UIStoryboard(name: name, bundle: nil)
        }
        else {
            storyboard = UIStoryboard(name: "\(T.self)", bundle: nil)
        }

        let vc: T!
        if let identifier = identifier {
            vc = storyboard.instantiateViewController(withIdentifier: identifier) as! T
        }
        else {
            vc = storyboard.instantiateInitialViewController()! as! T
        }
        self.addChildViewController(vc)
        self.view.addSubview(vc.view)
        return vc
    }
}

然而,当我像这样使用这个扩展名时:

class ChildViewController: UIViewController { /*...*/ }

class ParentViewController: UIViewController {
    private var childVC: ChildViewController!

    //...

    func setupSomeStuff() {
        self.childVC = self.instantiateChildViewController() //<-- Compiler error

        let vc: ChildViewController = self.instantiateChildViewController() //<-- Compiles!
        self.childVC = vc
    }
}

我在上面注释的行上得到了编译器错误Cannot assign value of UIViewController to type ChildViewController!。但是,如果我使用一个中间变量,我明确地给它一个类型。

这是一个Swift错误吗? (Xcode 8.1)我对泛型如何工作的解释是,在这种情况下,T应该等于更具体的ChildViewController,而不是受约束的UIViewController。如果我将childVC定义为private var childVC: ChildViewController?,我会得到同样的问题,我发现的唯一解决方法是局部变量,这显然会使扩展不那么引人注目,或者做一个明确的演员像:

self.childVC = self.instantiateChildViewController() as ChildViewController

1 个答案:

答案 0 :(得分:1)

我也见过这个。我认为围绕Optionals的一些奇怪的行为,编译器并没有像预期的那样处理。

如果将函数的返回值更改为可选值,则应该没有问题。

func instantiateChildViewController<T: UIViewController>(//whateverParams) -> T!

func instantiateChildViewController<T: UIViewController>(//whateverParams) -> T?

另外,如果您要在初始化程序以外的任何位置设置它,那么您的childVC应该是var而不是let。