Наблюдатели свойств
Часть раздела Объектно-ориентированное программирование путешествия по 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 -> 15willSet выполняется перед изменением, получая новое значение в 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 20didSet — подходящее место, чтобы поддерживать допустимое значение. Присваивание значения свойству внутри его собственного 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]Задание
ЛегкоЗавершите класс 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)")
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовМетоды и selfИнициализаторыКлассы — это ссылкиПовторение — читательский билет4Инкапсуляция
Контроль доступаТолько чтение извнеЗащита состоянияИнициализаторы с возможностью сбояПовторение — банковский счёт7Полиморфизм и обобщения
ПолиморфизмПриведение типовОбобщённые функцииОбобщённые типыПовторение — калькулятор фигур10Паттерны проектирования. Часть 2
Паттерн делегированияПаттерн декораторПаттерн строительПаттерн состояния2Структуры и типы-значения
СтруктурыСемантика значенийИзменяющие методыСтруктура или классПовторение — элемент инвентаря5Наследование
ПодклассыПереопределение методовИнициализаторы и superfinal и иерархииПовторение — иерархия сотрудников8Стандартные протоколы
CustomStringConvertibleEquatableComparableHashableПовторение — пользовательская сортировка11Проект: Управление библиотекой
Книги и читателиВыдача книг3Свойства: углублённое изучение
Вычисляемые свойстваНаблюдатели свойствСтатические членыПеречисления с методамиПовторение — журнал температурыПотренируйтесь самостоятельно: Песочница Swift