Menu
Coddy logo textTech

Наблюдатели свойств

Часть раздела Объектно-ориентированное программирование путешествия по Swift на Coddy. Урок 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, который исправляет значения за пределами этого диапазона и добавляет предупреждение low в alerts, если после исправления уровень оказывается ниже 20% от ёмкости (а предыдущий уровень не был низким).

Предоставленный код считывает ёмкость, а затем изменяет её на +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