Variable with Getter/Setter Cannot Have Initial Value, on Overridden Stored Property

Variable with getter/setter cannot have initial value, on overridden stored property

In swift you are able to override properties only with computed properties (which are not able to have default values) with same type. In your case, if you wish override test property in SecondViewController you need write something like this:

override var test: Float {
get {
return super.test
}
set {
super.test = newValue
}
}

And there is no way to override didSet/willSet observers directly; you may do this by write other methods invoked in observers and just override them:

FirstViewController:

internal var test: Float = 32.0 {
willSet {
test_WillSet(newValue)
}
didSet {
test_DidSet(oldValue)
}
}

func test_WillSet(newValue: Float) {}
func test_DidSet(oldValue: Float) {}

SecondViewController:

override func test_WillSet(newValue: Float) {
super.test_WillSet(newValue)
}
override func test_DidSet(oldValue: Float) {
super.test_DidSet(oldValue)
}

Set a default value for a property with defined getter and setter

In Swift, getters and setters are used for computed properties - there is no storage for the property and thus, in your case, simpleDescription can't be set in a setter.

If you need a default value, use:

class SimpleClass {
var simpleDescription: String = "default description"
}

if you want to initialize use:

class SimpleClass {
var simpleDescription: String
init (desc: String) {
simpleDescription = desc
}
}

You can only use the computed variable with both setter and getter to overriding the stored property of the superclass

You cannot override a stored property of the superclass, but you can change its value from the subclass:

class SuperClass {
var ID = 2202
}

class SubClass: SuperClass {
override init() {
super.init()
self.ID = 2203
}
}

let a = SuperClass()
let b = SubClass()

print(a.ID)
print(b.ID)

Overriding a stored property in Swift

Why am I not allowed to just give it another value?

You are definitely allowed to give an inherited property a different value. You can do it if you initialize the property in a constructor that takes that initial value, and pass a different value from the derived class:

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)

Overriding a property is not the same as giving it a new value - it is more like giving a class a different property. In fact, that is what happens when you override a computed property: the code that computes the property in the base class is replaced by code that computes the override for that property in the derived class.

[Is it] possible to override the actual stored property, i.e. lightSaberColor that has some other behavior?

Apart from observers, stored properties do not have behavior, so there is really nothing there to override. Giving the property a different value is possible through the mechanism described above. This does exactly what the example in the question is trying to achieve, with a different syntax.

Swift Programming: getter/setter in stored property

Ok. Reading through Apples documentation on Swift I found this:

If you assign a value to a property within its own didSet observer,
the new value that you assign will replace the one that was just set.

So all you have to do is this:

var rank: Int = 0 {
didSet {
// Say 1000 is not good for you and 999 is the maximum you want to be stored there
if rank >= 1000 {
rank = 999
}
}
}

Overriding computed property with stored one

There's no real technical reason why you cannot override a property with a stored property; it has getters and setters (accessors), which can override the accessors of the property to override. It should just be equivalent to overriding with a computed property that then forwards onto a stored property.

However I do foresee one slight complication with allowing this: property observer overrides.

Consider the following example:

class C {
var f: Int {
get { return 5 }
set { print("C says f was set") }
}
}

class D : C {
override var f: Int {
didSet {
print("D says f was set")
}
}
}

let d = D()
print(d.f)
d.f = 7
print(d.f)

// 5
// C says f was set
// D says f was set
// 5

We can override f's didSet in D. In this case, override var f: Int is essentially treated as a computed property with a getter and setter that forwards onto super, with an additional call onto the didSet implementation in the setter.

No actual storage is introduced by D here. So why is this problematic? Well, how would we tell the compiler that we do actually want storage for f? Adding an initialiser expression (= 10) could communicate that, but not all stored properties have default values; most are initialised from the class' designated initialiser. We'd probably need an attribute of some kind, but for such a limited use case, it doesn't seem like a particularly useful change to the language.

The lazy case is clear-cut because we cannot add property observers to them.

Although that all being said, the particular case you present should also be clear cut; as the base property only has a getter, so there's no property observers to override. I would recommend you file a bug to (hopefully) see what the Swift team have to say about this.

You can always achieve the same result with a computed property override that then forwards onto a stored property though:

class C {
var f: Int {
return 9
}
}

class D : C {

private var _f: Int = 10

override var f: Int {
get { return _f }
set { _f = newValue }
}
}

let d = D()
print(d.f) // 10
d.f = 7
print(d.f) // 7


Related Topics



Leave a reply



Submit