3

Can anyone explain the behaviour when subclassing properties? I am sure there is a good explanation for why 'override' does not actually override the property.

Why does Swift allow the surname property to be overridden but apparently still uses the super class's property and associated functions? They are not overridden.

It would seem that I would have to define some function that gets called in the didSet() method and override that to ensure the subclass does not inherit the super class's function as with the telephone property.

Is there any way to override a property's didSet() method? Creating some function that gets called seems to add an unnecessary extra complexity?

What is the correct way of achieving this?

import Cocoa

class BaseClass {
    var _name: String?
    var name: String? {
        get {
            return _name
        }
        set {
            _name = newValue
            print("BaseClass \(name)")
        }
    }

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

    var telephone: String? {
        didSet {
            telephoneSet()
        }
    }

    func telephoneSet(){
        print("BaseClass \(telephone)")
    }
}

class SubClass: BaseClass {
    override var name: String? {
        get {
            return _name
        }
        set {
            _name = newValue
            print("SubClass \(name)")
        }
    }
    override var surname: String? {
        didSet {
            print("SubClass \(surname)")
        }
    }

    override func telephoneSet(){
        print("SubClass \(telephone)")
    }
}


let object = SubClass()

object.name = "Jenny"
object.surname = "Jones"
object.telephone = "10810"

Generates the following output:

SubClass Optional("Jenny")
BaseClass Optional("Jones")
SubClass Optional("Jones")
SubClass Optional("10810")
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Duncan Groenewald
  • 8,496
  • 6
  • 41
  • 76
  • 3
    Unrelated but important: don't write getters and setters in Swift. https://github.com/amomchilov/Blog/blob/master/Stop%20writing%20getters%20and%20setters%20in%20Swift.md – Alexander Jun 02 '19 at 02:06
  • Keep in mind that `surname` is a stored property and `name` is a computed` property. – rmaddy Jun 02 '19 at 02:39
  • 1
    Related: [Override property observer](https://stackoverflow.com/questions/29503482/override-property-observer) – rmaddy Jun 02 '19 at 02:44
  • Take a look at this comment: https://stackoverflow.com/a/38224863/6580582 – Kevin Bai Jun 02 '19 at 03:10

1 Answers1

3

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.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • thanks nice clear explanation- I must have missed the part about adding the observer in the docs and was under the impression the didSet() would be overridden - but makes perfect sense now. – Duncan Groenewald Jun 02 '19 at 11:52
  • Is there anyway to override the observation? ie not _add_ an observer? – mfaani Dec 18 '20 at 00:12
  • Not as far as I know. In keeping with the open-closed principle, types are should be open for extension, but closed for change. So you really should only add behaviors, not change behaviors. – Rob Dec 18 '20 at 01:34