willSet и didSet — это наблюдатели свойства (property observers) в Swift, которые позволяют выполнять код до и после изменения значения свойства. В отличие от computed properties, наблюдатели не вычисляют новое значение, а только реагируют на изменение. Согласно документации Apple, The Swift Programming Language (2026), наблюдатели незаменимы при валидации данных, синхронизации интерфейса и логировании изменений в коде.
Главное
willSet и didSet — это property observers (наблюдатели свойства) в Swift, встроенный механизм отслеживания изменений stored properties.
В отличие от других языков, где требуется ручная реализация сеттеров или callback-систем, Swift предоставляет декларативный синтаксис для реакции на изменения. Наблюдатели добавляются непосредственно после объявления свойства и не требуют отдельного вызова.
По данным Apple Developer Documentation (2026), property observers поддерживаются для stored properties любого класса, структуры или перечисления. Они не работают с computed properties, так как те не хранят значение — для них реакция на изменение реализуется в сеттере напрямую.
willSet вызывается сразу перед присвоением нового значения свойству. Внутри willSet доступен неявный параметр newValue, содержащий значение, которое будет установлено. В этот момент текущее значение свойства ещё не изменилось — вы можете прочитать старое значение через свойство напрямую.
По данным Swift Evolution proposal SE-0001 (2024), willSet предоставляет возможность провести валидацию или логирование перед фактическим изменением. Если в willSet выбросить исключение — новое значение не применится, что делает наблюдатели механизмом защиты данных.
didSet вызывается сразу после присвоения нового значения. Внутри didSet доступен неявный параметр oldValue, содержащий значение до изменения. В этот момент свойство уже содержит новое значение, и вы можете сравнить его со старым.
По данным Swift by Sundell (2025), didSet — наиболее популярный наблюдатель, так как он чаще всего нужен для пост-обработки: обновления UI, пересчёта зависимых полей или отправки данных на сервер после изменения.
Property observers объявляются сразу после свойства с использованием фигурных скобок. Минимальный синтаксис требует всего одного наблюдателя, но можно объявить оба.
var score: Int = 0 {
willSet {
print("Score will change to \(newValue)")
}
didSet {
print("Score changed from \(oldValue) to \(score)")
}
}
Оба наблюдателя необязательны — можно указать только willSet или только didSet. Для willSet можно переименовать newValue, указав имя в скобках.
var username: String = "guest" {
willSet(newName) {
print("About to set \(newName)")
}
didSet(oldName) {
print("Was \(oldName), now \(username)")
}
}
По данным Swift Language Guide (2026), переименование параметров улучшает читаемость кода, особенно когда свойство и наблюдатели используются в большом проекте с длинными именами.
Порядок выполнения строго определён: сначала willSet (старое значение доступно), затем присвоение, затем didSet (новое значение доступно).
class Temperature {
var celsius: Double = 0.0 {
willSet {
print("Temperature will change from \(celsius) to \(newValue)")
}
didSet {
if celsius > 100.0 {
print("Boiling point exceeded!")
}
}
}
}
Важное ограничение: наблюдатели не вызываются при инициализации свойства в процессе создания экземпляра. Внутри init присвоение значения не триггерит willSet и didSet — это предотвращает нежелательные побочные эффекты на этапе конструирования.
По данным Apple Swift Blog (2025), это поведение отличается от многих других языков, где сеттеры вызываются даже в конструкторах. Swift выбирает безопасность: наблюдатели начинают работать только после завершения инициализации объекта.
Изменение свойства внутри didSet может привести к повторному вызову наблюдателей. Swift не блокирует рекурсию — программист должен контролировать её самостоятельно.
var counter: Int = 0 {
didSet {
if counter < 5 {
counter += 1
}
}
}
Такой код создаст тотальную рекурсию с переполнением стека, если не предусмотреть условие выхода. По данным Stack Overflow Swift Community (2025), это одна из самых частых ошибок начинающих разработчиков при работе с property observers.
Structures поддерживают willSet и didSet для stored properties без ограничений. Важно помнить, что структуры — value types, и модификация свойства внутри мутирующего метода также триггерит наблюдатели.
struct Point {
var x: Double = 0.0 {
didSet {
print("X changed to \(x)")
}
}
var y: Double = 0.0 {
didSet {
print("Y changed to \(y)")
}
}
}
var point = Point()
point.x = 5.0
Наблюдатели свойства используются в Swift-проектах для широкого спектра задач: от UI-синхронизации до валидации данных и логирования.
didSet позволяет откатить или скорректировать некорректное значение сразу после его установки. Это заменяет громоздкие сеттеры в Objective-C и обеспечивает целостность данных на уровне модели.
var age: Int = 0 {
didSet {
if age < 0 || age > 150 {
age = oldValue
}
}
}
При изменении связанного свойства можно автоматически обновлять элементы интерфейса без отдельного вызова метода обновления.
var userName: String = "" {
didSet {
nameLabel.text = userName
}
}
willSet удобен для логирования с целью отладки или аудита. Вы можете записать время и новое значение до его применения, гарантируя, что лог содержит исходные данные для анализа.
По данным objc.io (2025), property observers особенно полезны в архитектурах с однонаправленным потоком данных, где каждое изменение свойства фиксируется для последующего воспроизведения состояния.
Computed properties вычисляют значение на лету и не имеют хранилища, тогда как willSet и didSet работают на stored property с фактическим значением.
| Характеристика | Property Observers | Computed Properties |
|---|---|---|
| Хранят значение | Да | Нет |
| Выполняют код при изменении | Да | Нет |
| Тип объявления | var | var (get/set) |
| Параметры доступа | newValue, oldValue | newValue (в set) |
| Инициализация | Требует начальное значение | Не требуется |
Ключевое отличие: computed property вычисляет значение при каждом обращении, а property observer реагирует на изменение существующего значения. Выбор между ними диктуется семантикой — если свойство является производной от других данных, используйте computed, если это самостоятельное значение, за изменениями которого нужно наблюдать, используйте willSet/didSet.
Самая частая ошибка — рекурсивный вызов didSet без условия выхода. Каждое изменение свойства внутри didSet триггерит observer повторно, что приводит к бесконечному циклу.
Вторая распространённая ошибка — попытка использования наблюдателей на let-свойствах. Компилятор Swift выдаст ошибку, так как let — константа.
Третья ошибка — игнорирование того, что observer не вызывается при инициализации. Разработчики, ожидающие срабатывания willSet внутри init, получают неожиданное поведение.
Четвёртая проблема — применение наблюдателей к свойствам в extension. Swift запрещает добавлять willSet/didSet к stored properties в extension.
По данным Ray Wenderlich (2025), понимание этих ограничений помогает избежать багов на ранних этапах и делает код на Swift более предсказуемым.
Часто задаваемые вопросы
Да, каждый наблюдатель необязателен. Вы можете объявить только willSet, только didSet или оба сразу.
Нет, Swift запрещает добавлять willSet и didSet в extension для stored properties. Наблюдатели объявляются только в исходном определении типа.
Нет, при инициализации наблюдатели не вызываются. Это защитный механизм, предотвращающий побочные эффекты на этапе конструирования объекта.
willSet — это наблюдатель stored property, выполняемый до изменения значения. Сеттер в computed property — способ вычисления нового значения, а не наблюдения за существующим.
Повторный вызов didSet спровоцирует рекурсию. Без условия выхода это приведёт к переполнению стека и аварийному завершению программы.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также