Как работает геттер и сеттер вычисляемого свойства в Swift?
Что проверяют
Понимаете ли вы разницу между хранимым и вычисляемым свойством и что на самом деле происходит при чтении и записи. Следом обычно спрашивают про willSet и didSet, про lazy и про то, почему в расширении нельзя объявить хранимое свойство.
Как отвечать
Вычисляемое свойство не хранит значения: get выполняется при каждом чтении, set при каждой записи. По сути это пара методов с синтаксисом свойства.
- только
var: даже свойство с одним геттером объявляется черезvar, потому что его значение может меняться; - короткая форма: без
setможно опуститьgetи лишние скобки, а для одного выражения не нужен иreturn:var area: Double { width * height }; newValue: так по умолчанию называется присваиваемое значение вset, но имя можно задать своё:set(newArea) { ... };- нет сеттера без геттера: записывать можно только в свойство, которое умеет читаться;
- в структурах сеттер неявно
mutating, поэтому у экземпляра, объявленного черезlet, записать в такое свойство нельзя; - в протоколе требование
var area: Double { get set }выполняется и хранимым, и вычисляемым свойством; - эффекты: геттер свойства только для чтения может быть
get async throws.
Хороший пример: celsius хранится, а fahrenheit вычисляется в геттере и в сеттере пересчитывает celsius. Источник правды один, рассинхронизации нет.
Наблюдатели willSet и didSet вешаются на хранимые свойства. На собственное вычисляемое их не повесить, код и так пишется в сеттере. Но в наследнике при переопределении наблюдатели можно добавить и к унаследованному вычисляемому свойству.
Где спотыкаются
Внутри геттера обращаются к самому свойству (get { area }) и получают бесконечную рекурсию. Значение нужно хранить в отдельном приватном поле.
Кладут в геттер тяжёлую работу, например создание DateFormatter или разбор JSON. Она выполнится при каждом обращении, в том числе при каждой перерисовке SwiftUI.
Пишут сеттер, не согласованный с геттером: после rect.area = 40 чтение возвращает не 40. Сеттер должен сохранять инвариант «что записал, то и прочитал».