我有一些重复的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!。但是,如果我使用一个中间变量,我显式地给它指定一个类型,它就可以工作。
这是一只敏捷的虫子吗?(Xcode 8.1)我对泛型工作原理的解释是,在这种情况下T应该等于更具体的ChildViewController,而不是更少约束的UIViewController。如果我将childVC定义为private var childVC: ChildViewController?,我会遇到同样的问题,我找到的唯一解决方法是局部变量,这显然会降低扩展的吸引力,或者进行如下显式转换:
self.childVC = self.instantiateChildViewController() as ChildViewController

最佳答案

我也见过。我认为编译器没有按预期处理的选项有一些奇怪的行为。
如果将函数的返回值更改为可选值,它应该可以正常工作。
func instantiateChildViewController<T: UIViewController>(//whateverParams) -> T!

func instantiateChildViewController<T: UIViewController>(//whateverParams) -> T?
另外,如果要将childVC设置为初始值设定项以外的任何位置,那么它应该是var而不是let

10-02 02:27
查看更多