ios - Swift 覆盖 var 继承
问题描述
我正在尝试在 Swift 中做这样的事情。
public class BaseModel {
}
public class SubModel:BaseModel {
}
public class BaseClass {
public var model:BaseModel
init(_ model:BaseModel) {
self.model = model
}
}
public class SubClass: BaseClass {
override var model:SubModel
}
但是编译器不允许我用子类覆盖模型对象。是否有可能使用继承在 Swift 中实现我在上面尝试做的事情?
解决方案
正如所写,这不是类型安全的。您的界面要求必须subclass.model = model
适用于任何模型(在这个特定示例中,SubClass(model)
对于任何模型也是“合法的”,因为它当前正在继承 init)。
我相信你真正的意思是所有BaseClass都可以返回一个Model,但SubClass只能用SubModel设置。
如何解决这个问题在很大程度上取决于 SubClass 的用户是什么样子以及您为什么要进行继承。作为一项规则,你应该对 Swift 中的继承犹豫不决。它完全受支持,但 Swift 倾向于使用其他工具而不是类继承。
此特定示例的常见解决方案是通用解决方案,例如:
// Place any general Model requirements here.
public protocol BaseModel {}
// Just marking things final to emphasize that subclassing is not required
// These can all also be structs depending on if you need values or references
public final class SubModel: BaseModel {}
public final class BaseClass<Model: BaseModel> {
var model: Model
init(_ model: Model) {
self.model = model
}
}
// You can typealias specific instances if that helps
// With this, the syntax is extemely close to what you were trying to do
typealias SubClass = BaseClass<SubModel>
let sc = SubClass(SubModel())
let model: BaseModel = sc.model
// But, it's type safe
public final class OtherModel: BaseModel {}
sc.model = OtherModel // Cannot assign value of type OtherModel to type SubModel
let bad = SubClass(OtherModel()) // Cannot convert value of type 'OtherModel' to expected argument type 'SubModel'
如果 BaseClass 和 SubClass 更复杂,并且对它们有更多的内部逻辑,那么您可以升级到这些协议,但这取决于您要解决的特定问题。对于您所描述的情况,我通常会从泛型开始。
您不能在 Swift 中更改存储属性的类型。但是协变覆盖适用于方法和计算属性。所以只要你做model
了一个计算属性,你就可以在这里使用继承,但是在这样做的时候你必须非常小心以避免崩溃。
最简单的方法是向 SubClass 添加一个具有自己名称的新属性:
var subModel: SubModel { model as! SubModel }
但是要获得您要求的覆盖行为,您需要创建model
一个计算属性:
public class BaseClass {
private var _model: BaseModel
public var model: BaseModel { _model }
init(_ model:BaseModel) {
self._model = model
}
}
然后你可以在子类中覆盖model
:
public class SubClass: BaseClass {
public override var model: SubModel { super.model as! SubModel }
init(_ model: SubModel) {
super.init(model)
}
}
但请注意,这是危险的。SubClass 的子类或子类有可能BaseClass
破坏不变量,然后这将崩溃。要解决这个问题,您应该创建_model
一个let
值,并创建 SubClass final
:
public class BaseClass {
private let _model: BaseModel
public var model: BaseModel { _model }
init(_ model:BaseModel) {
self._model = model
}
}
public final class SubClass: BaseClass {
public override var model: SubModel { super.model as! SubModel }
init(_ model: SubModel) {
super.init(model)
}
}
所有这一切都很尴尬,很难保持正确。在所有 OOP 语言中保持类继承正确是很困难的,这会导致很多错误。这就是为什么 Swift 鼓励其他工具,比如泛型,来解决这些问题。它们更容易正确编写,编译器可以捕捉到你的错误。
推荐阅读
- oracle - 通过 id 连接 Oracle 中的两个表
- java - 在 JAX-RS 请求过滤器中添加响应标头
- python - 有效地将数组的 ID-值对转换为每个 ID 的数组 - NumPy
- javascript - 为什么我的 useRef 与状态不更新相关联?
- amazon-ec2 - Terraform:如何在 aws_lb 中为子网循环 aws_instances
- javascript - Ionic 5 Modal 仅显示按钮而没有其他内容 - React
- javascript - 重新渲染组件 ReactJs
- json.net - 严重性代码描述项目文件行抑制状态错误找不到版本12.0.3的包Newtonsoft.Json
- svg - 如何在d3.js中的面积图的任意两点之间添加非线性曲线
- java - 内部编译器错误:org.eclipse.jdt.internal.compiler.problem.ProblemHandler.handle 处的 java.lang.NullPointerException(ProblemHandler.java:148)