Search code examples
swiftinheritancesubclassgetter-setter

How can I change the property value in subclass within swift?


According to swift language guide's Inheritance chapter, I tried to code compuputed peoperty in subclass. When I set newValue to the property of the class's instance, the setter seemed to work, while the property value did not convert into the newValue.

class Vehicle {
    var currentSpeed = 1.0
    var description: String {
        return "The current speed is \(currentSpeed) miles per hour"
    }
    func makeNoise() {
    }
}
class Car: Vehicle {
    var gear = 0
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}
class AutomaticCar: Car {
    override var currentSpeed: Double {
        get {
            return super.currentSpeed
        }
        set {
            gear = Int(newValue/10) + 1
        }
    }
}

let automaticCar = AutomaticCar()
automaticCar.currentSpeed = 12.0
print(automaticCar.currentSpeed)//It prints "1.0"
print(automaticCar.description)//It prints "The current speed is 1.0 miles per hour in gear 2"

The property value of automaticCar.currentSpeed is still "1.0" rather than "12.0", while the instance's gear property seems to effect. I have searched but could't find the answer, what principle leads to this situation?

Further question:

class A {
    var test1 = 1
    var test2 = 2
    var sum: Int {
        get {
            return test1 + test2
        }
        set {
            test1 = newValue - test2
        }
    }
}
var a = A()
print(a.sum)
a.sum = 4
print(a.sum)//It ptints "4"
print(a.test1)//It prints "2"

In this case, I don't need to set the value of new sum property deliberately, What's the differece between two cases?


Solution

  • In your real example:

    • Vehicle currentSpeed is a stored property. That means you can assign to it directly and the property value changes.

    • AutomaticCar currentSpeed is effectively a different property — a computed property. That means that when you assign to it, all that happens is that the set function runs. No stored property values change as a result, unless you change them, right here, in the set function.

    Well, in your AutomaticCar's currentSpeed set function, you didn't store the new value in the stored property, Vehicle's currentSpeed. Therefore it didn't change, because nothing happened that would change it.

    As Hamish rightly says in a comment, what you meant to say is probably this:

    class AutomaticCar: Car {
        override var currentSpeed: Double {
            didSet {
                self.gear = Int(self.currentSpeed/10) + 1
            }
        }
    }
    

    In that formulation, AutomaticCar currentSpeed is not a computed property; it is Vehicle currentSpeed — it is the very same stored property, along with a setter observer. So setting it sets it, storing the new value — plus now we run the setter observer and make the change in self.gear that you are after.

    Note that the override of a stored property in a subclass must be one or the other, either an independent computed property or else the original stored property with the addition of a setter observer. It cannot of itself be an independent stored property.