为什么 didSet 不起作用?

Why doesn't didSet work?

在许多 didSet 的示例中,我在 SO 上看到,此代码将 return 0,但是,除了原始值。我做错了什么?

Swift

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

var circ = Circle(radius: -25)

print(circ.radius)

输出

-25

didSet 不会在初始化期间调用,只会在之后调用。如果您想在初始化期间验证数据,您的初始化程序应该这样做。

如果您添加:

circ.radius = -50
print(circ.radius)

您会看到它按预期工作,输出将是 0.0

正如 Paul 在评论中所写,属性 观察者 didSetwillSet 在值初始化期间不会被调用。

如果你想在初始化时也调用它们来获取值,你可以添加一个函数调用来重新设置 radius 属性 在初始化程序中初始设置后:

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

    init(radius: Double) {
        self.radius = radius
        setRadius(radius) // <-- this will invoke didSet
    }

    mutating func setRadius(radius: Double) {
        self.radius = radius
    }
}

var circ = Circle(radius: -25)

print(circ.radius) // 0.0

你可以确保 didSetinit 中,如果你把它放在 defer 语句中。也适用于 deinit

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

    init(radius: Double) {
        defer { self.radius = radius }
    }
}

为此使用初始化:

struct Circle {
    var radius: Double

    init(radius: Double) {
        self.radius = radius < 0 ? 0 : radius
    }
}

var circ = Circle(radius: -25)

print(circ.radius)

0.0

你也可以使用 lazy 和 init(radius ....

struct Circle {
    lazy var radius: Double = 0.0 {
        didSet {
            print("didSet called")
            if radius < 0 {
                radius = 0
            }
        }
    }
    init(radius:Double) {
        self.radius = radius
    }
}