Override Property Observer

Override property observer

You can override the set and get part of the property and move your println there. This way Swift won't call the original code -- unless you call super.

class Foo {
private var _something: Int!

var something: Int! {
get {
return _something
}
set {
_something = newValue
println("vroom")
}
}
}

class Bar: Foo {
override var something: Int! {
get {
return _something
}
set {
_something = newValue
println("toot toot")
}
}
}

That's not pretty, though.

Here's a better -- and simpler -- solution:

class Foo {
var something: Int! {
didSet {
somethingWasSet()
}
}

func somethingWasSet() {
println("vroom")
}
}

class Bar: Foo {
override func somethingWasSet() {
println("toot toot")
}
}

Since there is no way to "override" the didSet, what remains is overriding a secondary function especially created for that purpose.

Swift property observing doesn't override

Inheritance section of The Swift Programming Language (Swift 2.2) describes 'overriding property observers' as 'adding property observers'

Overriding Property Observers

You can use property overriding to add property observers to an
inherited property...

If a subclass were able to override didSet observer of currentSpeed property of AutomaticCar class in the following example:

class AutomaticCar {
var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) + 1
}
}
}

The didSet in the subclass would prevent updating gear property which could break the designed behavior of the super class, AutomaticCar.

Overriding didSet

I have tried your code in a playground and got and error

Variable with getter/ setter cannot have and initial value.

So I just removed ="" from the orverriding variable. like below:

class Foo {
var name: String = "" { didSet { print("name has been set") } }
}

class Bar: Foo {
override var name: String {
didSet {
print("print this first")
// print the line set in the superclass
}
}
}

let bar = Bar()
bar.name = "name"

and that's what I got in consol:

name has been set
print this first

What is the right way to override a property in a subclass in Swift?

I don't get that error in 6.1, but the underlying problem is you have an infinite loop here. What you meant to say is:

// This is wrong, but what you meant
override var someStoredProperty: Int? {
willSet {
super.someStoredProperty = newValue! + 10
}
}

Note the super. (Which is yet another reason I strongly recommend using self. on properties, to make it clear when these infinite loops exist.)

But this code is meaningless. Before setter, you set the value to x + 10. You then set the value to x. What you really meant was:

override var someStoredProperty: Int? {
didSet {
if let value = someStoredProperty {
super.someStoredProperty = value + 10
}
}
}

Override property in Swift subclass

Let’s reduce the example:

class BaseClass {
var surname: String? {
didSet { print("BaseClass \(surname)") }
}
}

class SubClass: BaseClass {
override var surname: String? {
didSet { print("SubClass \(surname)") }
}
}

Then:

let object = SubClass()
object.surname = "Jones"

Will produce:

BaseClass Optional("Jones")

SubClass Optional("Jones")

The above is not overriding the stored property, surname, with another stored property. There is only the stored property of the base class and the subclass is simply adding its own observer to this property. I refer you to The Swift Programming Language: Inheritance: Overriding, which says:

Overriding Property Observers


You can use property overriding to add property observers to an inherited property. This enables you to be notified when the value of an inherited property changes, regardless of how that property was originally implemented.

In your example of name, you are overriding the computed property with the subclasses’ own computed property. Likewise, in your example of telephoneSet, you are also overriding the method with the subclasses’ own method. But with surname, you’re not overriding the base classes’ property, but merely letting the subclass add an observer to the base classes’ stored property.

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

Mixing Swift Property Observers and Inheritance

The order of the didSet calls is as expected - each child calls it's willSet, then calls super, then calls it's didSet. If you did it with literal calls to super.pause you'd have something like this, which makes the order of the didSet calls clear:

class A {
var paused:Bool = false

func pause(_ paused:Bool) {
print("Class A will set paused")
self.paused=paused
print("Class A did set paused")
}
}

class B : A {
override func pause(_ paused:Bool) {
print("Class B will set paused")
super.pause(paused)
print("Class B did set paused")
}
}

class C : B {
override func pause(_ paused:Bool) {
print("Class C will set paused")
super.pause(paused)
print("Class C did set paused")
}
}

let testC = C()
testC.pause(true)

Implement variable attribute property observer in Swift

You can make a property like this

    var hideLabel: Bool = false {
didSet {
myLabel.isHidden = hideLabel
//SHOW OR HIDE OTHER VIEWS
}
}

By doing this you don't have to use KVO at the same time you can add more controls to hide to show at didSet context.
I Believe this is a simpler way to do such a thing.



Related Topics



Leave a reply



Submit