我有一些重复的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