Menu
CoddyTech

属性观察器

本课属于 Coddy Swift 学习旅程的“面向对象编程”单元。第 13 课,共 57 课。

属性观察器会在存储属性发生变化时运行代码。didSet会在新值存储后立即运行,在其中,oldValue保存的是之前的值:

class Player {
    var score = 0 {
        didSet {
            print("score \(oldValue) -> \(score)")
        }
    }
}

let p = Player()
p.score = 10
p.score += 5

输出:

score 0 -> 10
score 10 -> 15

willSet 会在更改前运行,并将即将设置的值作为 newValue。属性获得初始值时,不会运行观察器:

struct Thermostat {
    var target = 20 {
        willSet { print("changing to \(newValue)") }
        didSet { print("changed from \(oldValue)") }
    }
}

var t = Thermostat()
t.target = 22

输出:

changing to 22
changed from 20

didSet 是保持值有效的好地方。在属性自己的 didSet 中赋值,不会再次触发观察器:

struct Volume {
    var level = 5 {
        didSet {
            if level > 10 { level = 10 }
            if level < 0 { level = 0 }
        }
    }
}

var v = Volume()
v.level = 42
print(v.level)
v.level = -3
print(v.level)

输出:

10
0

观察器还可以记录历史记录或更新相关状态,这样逻辑就会放在属性旁边,而不是散落在代码各处:

class Account {
    var history: [Int] = []
    var balance = 0 {
        didSet { history.append(balance - oldValue) }
    }
}

let a = Account()
a.balance = 100
a.balance = 70
print(a.history)

输出:

[100, -30]
challenge icon

挑战

简单

补全类 Tank。它的存储属性 level 必须保持在 0 和 capacity 之间:添加一个 didSet,用于修正超出此范围的值;如果修正后的等级低于容量的 20%,且之前的等级不低,则将警告 low 添加到 alerts 中。

提供的代码会读取容量,然后根据 +n 或 -n 更改等级。每次更改后,它都会输出等级,最后输出 alerts: 和警告数量。

你的代码要写在 Tank.swift 中。main.swift 中包含提供的输入输出代码,不能编辑。

亲手试试

// 提供的输入/输出代码:保持原样
var input: [String] = []
while let line = readLine() { input.append(line) }
let tank = Tank(capacity: Int(input[0])!)
for cmd in input.dropFirst() {
    let n = Int(cmd.dropFirst())!
    tank.level += cmd.hasPrefix("+") ? n : -n
    print(tank.level)
}
print("alerts: \(tank.alerts.count)")
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Swift 在线编辑器