ПрограммированиеiOS разработчик

Как работают свойства с наблюдателями (property observers) в Swift, и зачем они нужны?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Свойства с наблюдателями (property observers) в Swift позволяют реагировать на изменения значения свойства. Эта концепция появилась вместе с Swift для повышения прозрачности контроля над изменениями данных и автоматизации логики при изменениях.

История вопроса:

До Swift подобное поведение часто реализовывалось вручную через setter'ы или специальные методы. В Swift наблюдатели появились как стандартный инструмент в языке.

Проблема:

Разработчику важно уметь отлавливать момент изменения свойства — например, для обновления UI или валидации данных. Без наблюдателей код становился бы более громоздким и менее читаемым.

Решение:

В Swift доступно два основных наблюдателя:

  • willSet вызывается перед изменением значения
  • didSet вызывается после присваивания нового значения

Наблюдатели можно добавить к stored property, кроме lazy свойств и вычисляемых (computed) свойств.

Пример кода:

class Temperature { var celsius: Double { willSet { print("Скоро установится значение", newValue) } didSet { print("Значение было:", oldValue, ", а стало:", celsius) } } init(celsius: Double) { self.celsius = celsius } } let temp = Temperature(celsius: 22) temp.celsius = 28 // Выведет willSet и didSet

Ключевые особенности:

  • В наблюдателе willSet доступна специальная переменная newValue
  • В didSet — oldValue
  • Наблюдатели не вызываются при инициализации свойства в init

Вопросы с подвохом.

Можно ли добавить наблюдатели к вычисляемым (computed) свойствам?

Нет, к computed свойствам нельзя добавить willSet и didSet, поскольку у них уже есть собственные геттер и сеттер. Использование willSet/didSet актуально только для stored свойств.

Вызовутся ли наблюдатели при изменении свойства внутри инициализатора?

Нет, property observers не вызываются во время инициализации (init). Они срабатывают только при изменении значения после завершения init.

Что произойдет при присваивании текущего значения самому себе, например x = x?

Наблюдатели все равно вызовутся, даже если значение свойства не изменилось! Это может привести к побочному выполнению логики — будьте внимательны.

var value: Int = 0 { didSet { print("didSet всегда вызывается!") } } value = value // didSet вызовется

Типовые ошибки и анти-паттерны

  • Зависимость от side-effect: реализация бизнес-логики только во didSet/willSet делает код непрозрачным
  • Неправильное управление сторонними эффектами при "пустом" изменении значения, когда оно не поменялось
  • Использование наблюдателей для computed property вместо реализации behavoir в setter

Пример из жизни

Негативный кейс

Разработчик реализовал в didSet обновление интерфейса, но не контролировал изменение значения. UI обновлялся даже при "пустом" присваивании, что снизило производительность.

Плюсы:

  • Быстрая реализация, мало кода

Минусы:

  • Возросло количество ненужных операций, усложнена отладка

Позитивный кейс

В didSet проверялось равенство старого и нового значения. Обновление интерфейса происходило только если значение действительно изменилось.

Плюсы:

  • Минимизация side effects, высокая производительность

Минусы:

  • Потребовался дополнительный if-проверка, чуть больше кода