Inheritance 重写Swift中的存储属性

Inheritance 重写Swift中的存储属性,inheritance,swift,properties,overriding,Inheritance,Swift,Properties,Overriding,我注意到编译器不允许我用另一个存储值重写存储属性(这似乎很奇怪): 但是,我可以使用计算属性执行此操作: class Jedi { let lightSaberColor = "Blue" } class Sith: Jedi { override var lightSaberColor : String{return "Red"} } class Jedi { var lightSaberColor = "Blue" } class Sith: Jedi {

我注意到编译器不允许我用另一个存储值重写存储属性(这似乎很奇怪):

但是,我可以使用计算属性执行此操作:

class Jedi {
    let lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor : String{return "Red"}

}
class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override init() {
        super.init()
        self.lightSaberColor = "Red"
    }
}
为什么我不能给它另一个值

为什么用存储的属性进行覆盖是一件令人憎恶的事情,而用一个计算出的犹太洁食器进行覆盖呢?他们在想什么

为什么不允许我给它另一个值

您绝对可以为继承的属性赋予不同的值。如果在接受该初始值的构造函数中初始化属性,并从派生类传递不同的值,则可以执行此操作:

class Jedi {
    // I made lightSaberColor read-only; you can make it writable if you prefer.
    let lightSaberColor : String
    init(_ lsc : String = "Blue") {
        lightSaberColor = lsc;
    }
}

class Sith : Jedi {
    init() {
        super.init("Red")
    }
}

let j1 = Jedi()
let j2 = Sith()

println(j1.lightSaberColor)
println(j2.lightSaberColor)
重写一个属性与给它一个新值不同——它更像给一个类一个不同的属性。事实上,重写计算属性时会发生这种情况:在基类中计算属性的代码将替换为在派生类中计算该属性重写的代码

[是否]可以覆盖实际存储的属性,即具有其他行为的
lightSaberColor


除了观察者之外,存储的属性没有行为,因此实际上没有什么可以覆盖的。通过上述机制,可以为属性赋予不同的值。这正是问题中的示例试图实现的,使用了不同的语法。

您可能希望为属性分配另一个值:

class Jedi {
    let lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor : String{return "Red"}

}
class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override init() {
        super.init()
        self.lightSaberColor = "Red"
    }
}

对我来说,您的示例在Swift 3.0.1中不起作用

我在操场上输入了以下代码:

class Jedi {
    let lightsaberColor = "Blue"
}

class Sith: Jedi {
    override var lightsaberColor : String {
        return "Red"
    }
}
在Xcode中的编译时引发错误:

无法使用'var'的getter重写不可变的'let'属性'lightsaberColor'

不,您不能更改存储属性的类型。Liskov替换原则迫使您允许在需要超类的地方使用子类

但是如果将其更改为
var
,并因此在computed属性中添加
set
,则可以使用相同类型的computed属性覆盖存储的属性

class Jedi {
    var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
        set {
            // nothing, because only red is allowed
        }
    }
}
这是可能的,因为从存储属性切换到计算属性是有意义的

但是,使用存储的
var
属性重写存储的
var
属性没有意义,因为您只能更改属性的值

但是,您完全不能使用存储属性替代存储属性


我不会说西斯是绝地武士:-p。因此很明显,这是行不通的。

对于Swift 4,来自:

您可以重写继承的实例或类型属性以提供 您自己为该属性定制的getter和setter,或添加 属性观察者,以便在 基础属性值将更改


您还可以使用函数来覆盖。这不是直接的回答,但可以丰富这个话题)

甲级

override func viewDidLoad() {
    super.viewDidLoad()

    if shouldDoSmth() {
       // do
    }
}

public func shouldDoSmth() -> Bool {
    return true
}
B类:A

public func shouldDoSmth() -> Bool {
    return false
}

不幸的是,在Swift中,这是不可能做到的。最佳替代方案如下:

class Jedi {
    private(set) var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
    }
}

我在为视图控制器设置常量时遇到了同样的问题

由于我使用interface builder来管理视图,因此无法使用
init()
,因此我的解决方法与其他答案类似,只是在基类和继承类上都使用了只读计算变量

class Jedi {
    var type: String {
        get { return "Blue" }
    }
}

class Sith: Jedi {
    override var type: String {
        get { return "Red" }
    }
}

如果您试图在Swift 5中这样做,您将收到一封电子邮件

无法使用'var'的getter重写不可变的'let'属性'lightSaberColor'

最好将其声明为计算属性

这是因为我们正在重写
get{}
函数

class Base {
   var lightSaberColor: String { "base" }
}

class Red: Base {
   override var lightSaberColor: String { "red" }
}

Swift不允许您覆盖变量
存储属性
,您可以使用
计算属性

class A {
    var property1 = "A: Stored Property 1"

    var property2: String {
        get {
            return "A: Computed Property 2"
        }
    }

    let property3 = "A: Constant Stored Property 3"

    //let can not be a computed property
    
    func foo() -> String {
        return "A: foo()"
    }
}

class B: A {

    //now it is a computed property
    override var property1: String {

        set { }
        get {
            return "B: overrode Stored Property 1"
        }
    }

    override var property2: String {
        get {
            return "B: overrode Computed Property 2"
        }
    }
    
    override func foo() -> String {
        return "B: foo()"
    }

    //let can not be overrode
}
与Java相比,更为明显的是,类字段不能被重写,并且不支持多态性,因为它是在编译时定义的(高效运行)。它被称为变量隐藏不建议使用这种技术,因为它很难读取/支持


您可以使用此方法更新值

class A {

    var lightSaberColor : String = "Red"
}
您不需要重写变量。您可以更改变量的值

class B: A {
     * **Change Value when the class will initialize.**

     override init() {
        super.init()
          self.lightSaberColor = "Orange"
     }

    /*
     * **Change Value when you will use this function.**
     */
    func test() {
       lightSaberColor = "Green"
    }
}

let b = B()

b.test()

同样适用于上面的注释。虽然这个代码片段可以解决这个问题,但它确实有助于提高文章的质量。请记住,您将在将来回答读者的问题,而这些人可能不知道您的代码建议的原因。@MaxMacLeod除了观察者之外,存储的属性没有行为,因此实际上没有什么可以替代的。他想在子类中为存储的属性赋予不同的值,但他不确定实现它的机制。答案解释了如何在Swift中实现。我很抱歉回复太晚,看来你的评论引起了足够的混乱,吸引了反对票,所以我决定解释一下到底发生了什么。
class B: A {
     * **Change Value when the class will initialize.**

     override init() {
        super.init()
          self.lightSaberColor = "Orange"
     }

    /*
     * **Change Value when you will use this function.**
     */
    func test() {
       lightSaberColor = "Green"
    }
}

let b = B()

b.test()