首页 > 解决方案 > 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 中实现我在上面尝试做的事情?

标签: iosswiftinheritance

解决方案


正如所写,这不是类型安全的。您的界面要求必须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 鼓励其他工具,比如泛型,来解决这些问题。它们更容易正确编写,编译器可以捕捉到你的错误。


推荐阅读