Swift3.0 利用泛型设置基类属性的动态类型
原文链接
在MVVM架构的项目中,我们一般会写一个viewModel的基类和一个controller的基类,在controller的对象中持有viewModel,如下代码
class ViewModel{
}
class Controller {
var viewModel:ViewModel
init(viewModel:ViewModel) {
self.viewModel = viewModel
}
}
然后在每一个具体的页面上,都会写一个对应的viewModel和controller分别继承自上面两个基类
class Sub1ViewModel:ViewModel{
let desc = "Sub1"
}
class Sub1Controller:Controller{
}
这时如果我想在Sub1Controller中访问Sub1ViewModel中的desc变量,只能在Sub1Controller中这样写
class Sub1Controller:Controller{
var description{
let viewModel = self.viewModel as! Sub1ViewModel
return viewModel.desc
}
}
由于Swift是强类型语言,不能像OC那样通过类型的强制转换来使基类的属性变成子类的类型,所以你每次使用基类的属性的时候都必须要用as强制转换成子类的类型之后才能访问子类的属性或者方法,当然你可以将这个强制转换包装成一个函数,或者提供另一个变量返回强制转换过的类型。
class Sub1Controller:Controller{
var sub1ViewModel:Sub1ViewModel{
return self.viewModel as! Sub1ViewModel
}
var description{
// let viewModel = self.viewModel as! Sub1ViewModel
return self.sub1ViewModel.desc // Or: return self.sub1ViewModel().desc
}
func sub1ViewModel() -> Sub1ViewModel{
return self.viewModel as! Sub1ViewModel
}
}
但是这两种方法仍然不够优雅,产生了很多冗余的代码,笔者在实践中尝试着使用泛型来是基类的属性类型动态化,是代码看起来更优雅
class ViewModel{
}
class Controller<ModelType:ViewModel> {
var viewModel:ModelType
init(viewModel:ModelType) {
self.viewModel = viewModel
}
}
class Sub1ViewModel:ViewModel{
let desc = "Sub1"
}
class Sub1Controller:Controller<Sub1ViewModel>{
var description{
return self.viewModel.desc
}
}
通过ModelType泛型类型,使得在Sub1Controller中直接通过viewModel就能访问到Sub1ViewModel的属性