Tom
Tom

Reputation: 1

Why does the '=' assignment operator not work in my if statement in my didSet property observer?

struct Circle {
    // Properties

    var radius: Double {
        didSet {
            if oldValue < 0 {
                 radius = 0
            }
        }
    }
    var area:Double {
        get{
            return Double.pi * pow(radius, 2)
        }
    }
    var circumference: Double {
        get {
            return 2 * radius * Double.pi
        }
    }
    init() {
        radius = 0
    }
    init(radius r: Double) {
        radius = r
    }

}

// test circle

var testCircle = Circle()
print ("radius:", testCircle.radius, "area: ", testCircle.area, "circumference: ", testCircle.circumference)

var testCircle2 = Circle(radius: 2.5)
print("radius: ", testCircle2.radius, " area: ", testCircle2.area, "circumference: ", testCircle2.circumference)

var testCircle3 = Circle(radius: 20)
print("radius: ", testCircle3.radius, "area: ", testCircle3.area, "circumference: ", testCircle3.circumference)

var testCircle4 = Circle(radius: -4.5)
print("radius: ", testCircle4.radius, "area: ", testCircle4.area, "circumference: ", testCircle4.circumference)

Upvotes: 0

Views: 151

Answers (2)

rmaddy
rmaddy

Reputation: 318814

Remember, didSet is called after the property has actually been changed. oldValue will contain the previous value.

You want to check if the new value is negative.

Update the code to:

var radius: Double {
    didSet {
        if radius < 0 {
            radius = 0
        }
    }
}

You want to check if radius (the latest value) is negative.

You also need to update your init method:

init(radius r: Double) {
    radius = r >= 0 ? r : 0
}

This is because didSet and willSet are not called during initialization. So your init method needs to validate the parameter.

As a side note can further simplify your radius and circumference properties as follows:

var area:Double {
    return Double.pi * pow(radius, 2)
}

A read-only computer property doesn't need the get { }.

Upvotes: 1

Clay Ellis
Clay Ellis

Reputation: 5330

didSet property observers aren't called during init. You can wrap the assignment in a defer { ... } statement to force didSet to be called.

For example:

init(radius r: Double) {
    defer { radius = r }
}

If you'd like the default radius to be 0, I'd recommend using a default parameter value for radius like so:

init(radius r: Double = 0) {
    defer { radius = r }
}

...that way you avoid having two init methods and still initialize a Circle as Circle() (radius = 0) and as Circle(radius: 3) (radius = 3).

Upvotes: 2

Related Questions