在 Swift 中重写存储属性

我注意到编译器不允许我用另一个存储值覆盖一个存储属性(这看起来很奇怪) :

class Jedi {
var lightSaberColor = "Blue"
}




class Sith: Jedi {
override var lightSaberColor = "Red" // Cannot override with a stored property lightSaberColor
}

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

class Jedi {
let lightSaberColor = "Blue"
}




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


}

为什么我不能给它另一个值?

为什么用一个存储属性重写是一件令人厌恶的事情,而用一个经过计算的洁净值来做这件事情?他们在想什么?

110794 次浏览

为什么我不能给它另一个值呢?

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

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()


print(j1.lightSaberColor)
print(j2.lightSaberColor)

重写一个属性并不等同于给它一个新值——它更像是给一个类一个不同的属性。实际上,这就是重写计算属性时发生的情况: 在基类中计算该属性的代码是 被取代了,由计算派生类中该属性的重写的代码执行。

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

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

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

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并因此在计算属性中添加 set,则可以使用相同类型的计算属性重写存储属性。

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。因此,很明显,这是行不通的。

class SomeClass {
var hello = "hello"
}
class ChildClass: SomeClass {
override var hello: String {
set {
super.hello = newValue
}
get {
return super.hello
}
}
}

来自 苹果的文档的 Swift 4:

可以重写要提供的继承实例或类型属性 您自己的自定义属性的 getter 和 setter,或者添加 属性观察器,以使重写属性能够观察 基础财产价值的变化。

你也可以使用一个函数来覆盖,这不是直接的回答,但是可以丰富这个主题)

A 级

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 不允许你覆盖 stored property。你可以使用 computed property代替它

class A {
//var
var property1 = "A: Stored Property 1"
var property2: String {
get {
return "A: Computed Property 2"
}
}


//let
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
}
func testPoly() {
let a = A()
    

XCTAssertEqual("A: Stored Property 1", a.property1)
XCTAssertEqual("A: Computed Property 2", a.property2)
    

XCTAssertEqual("A: foo()", a.foo())
    

let b = B()
XCTAssertEqual("B: overrode Stored Property 1", b.property1)
XCTAssertEqual("B: overrode Computed Property 2", b.property2)
    

XCTAssertEqual("B: foo()", b.foo())
    

//B cast to A
XCTAssertEqual("B: overrode Stored Property 1", (b as! A).property1)
XCTAssertEqual("B: overrode Computed Property 2", (b as! A).property2)
    

XCTAssertEqual("B: foo()", (b as! A).foo())
}

与 Java 相比,更加明显的是,类字段不能被覆盖,也不支持多态性,因为它是在编译时(高效运行)定义的。它被称为 变量隐藏< sup > [ About ] 不推荐使用这种技术,因为它很难阅读/支持

[迅速财产]

可以使用此方法更新值

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()

除上述例子外,

class SomeClass {
var hello = "hello"
}
class ChildClass: SomeClass {
override var hello: String {
set {
_hello = newValue
}
get {
_hello
}
}
private var _hello: String = ""
}




// Testing...
let c = ChildClass()
c.hello = "test"
print(c.hello) // test

我使用这种方法:

class Class {
    

private lazy var _instance: AType = {
return AType()
} ()
    

var instance: AType {
return _instance
}
    

}


class Subclass: Class {
    

private lazy var _instance: AType = {
return ASubType()
} ()
    

override var instance: AType {
return _instance
}
    

}
    //declaring class
class Games {
var  no_player:Int = 0
var name_game :String = ""
var player_value:String {
return "low"
}
func playing(){
print( "the \(name_game) is played by \(no_player) players and the player value is \(player_value)")
}
}
//chess class inherits Games
class Chess : Games {
var location:String = ""
}
//cricket class inherits Games
class cricket : Games{
var ball_brand = "sg"
}
//making object of Chess()
let Chess1 = Chess()
Chess1.name_game = "Chess "
Chess1.no_player = 2
Chess1.palying()
//polo inherits Games


class polo:Games {
override var player_value: String{
return "high"
}
        

override func playing() {
print("holla we are playing cricket with 10 members and the palyer value is  \(player_value) ")
}
}
var polo1 = polo()
polo1.playing()