我有一些重复的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
答案 0 :(得分:1)
我也见过这个。我认为围绕Optionals的一些奇怪的行为,编译器并没有像预期的那样处理。
如果将函数的返回值更改为可选值,则应该没有问题。
func instantiateChildViewController<T: UIViewController>(//whateverParams) -> T!
或
func instantiateChildViewController<T: UIViewController>(//whateverParams) -> T?
另外,如果您要在初始化程序以外的任何位置设置它,那么您的childVC应该是var而不是let。