Swift имеет синтаксис объявления свойства, очень похожий на C #:
var foo: Int {
get { return getFoo() }
set { setFoo(newValue) }
}
Тем не менее, это также имеет willSet
и didSet
действия. Они вызываются до и после вызова сеттера, соответственно. Какова их цель, учитывая, что вы можете просто иметь один и тот же код внутри сеттера?
get
&set
) в основном должно иметь свойство, вычисляемое на основе другого свойства, например, путем преобразования меткиtext
в годInt
.didSet
&willSet
есть, что сказать ... эй, это значение было установлено, теперь давайте сделаем это, например, Наш источник данных был обновлен ... поэтому давайте перезагрузим tableView, чтобы он включал новые строки. В качестве другого примера см . Ответ dfri о том, как вызывать делегатовdidSet
Ответы:
Суть в том, что иногда вам нужно свойство с автоматическим хранением и некоторым поведением, например, для уведомления других объектов о том, что это свойство только что изменилось. Когда все, что у вас есть, это
get
/set
, вам нужно другое поле для хранения значения. С помощьюwillSet
иdidSet
вы можете действовать, когда значение изменяется без необходимости в другом поле. Например, в этом примере:myProperty
печатает свое старое и новое значение каждый раз, когда оно изменяется. Мне нужны только геттеры и сеттеры:Так что
willSet
иdidSet
представляйте экономию в пару строк и меньше шума в списке полей.источник
willSet
иdidSet
не вызываются, когда вы устанавливаете свойство из метода init, как отмечает Apple:willSet and didSet observers are not called when a property is first initialized. They are only called when the property’s value is set outside of an initialization context.
myArrayProperty.removeAtIndex(myIndex)
... Не ожидается.Я понимаю, что установить и получить для вычисляемых свойств (без поддержки сохраненных свойств )
если вы исходите из Objective-C, имея в виду, что соглашения об именах изменились. В Swift iVar или переменная экземпляра называется сохраненным свойством
Пример 1 (свойство только для чтения) - с предупреждением:
Это приведет к предупреждению, потому что это приведет к рекурсивному вызову функции (геттер вызывает сам себя). Предупреждение в этом случае «Попытка изменить 'test' в своем собственном геттере".
Пример 2. Условное чтение / запись - с предупреждением
Аналогичная проблема - вы не можете сделать это, так как он рекурсивно вызывает сеттер. Также обратите внимание, что этот код не будет жаловаться на инициализаторы, так как нет сохраненного свойства для инициализации .
Пример 3. Чтение / запись вычисляемого свойства - с резервным хранилищем
Вот шаблон, который позволяет условную установку фактического сохраненного свойства
Заметка . Фактические данные называются _test (хотя это могут быть любые данные или комбинация данных). Обратите также внимание на необходимость предоставления начального значения (в качестве альтернативы вам необходимо использовать метод init), поскольку _test на самом деле является переменной экземпляра.
Пример 4. Использование воли и набора
Здесь мы видим, что willSet и didSet перехватывают изменение фактического сохраненного свойства. Это полезно для отправки уведомлений, синхронизации и т. Д. (См. Пример ниже)
Пример 5. Конкретный пример - контейнер ViewController
Обратите внимание на использование ОБА вычисленных и сохраненных свойств. Я использовал вычисляемое свойство, чтобы предотвратить установку одного и того же значения дважды (чтобы избежать неприятностей!); Я использовал willSet и didSet для пересылки уведомлений в viewController (см. Документацию UIViewController и информацию о контейнерах viewController)
Я надеюсь, что это поможет, и, пожалуйста, кто-то кричит, если я допустил ошибку где-нибудь здесь!
источник
//I can't see a way to 'stop' the value being set to the same controller - hence the computed property
предупреждение исчезнет после того, как я использовалif let newViewController = _childVC {
вместоif (_childVC) {
get
я думаю, вам нужно добавить,if _childVC == nil { _childVC = something }
а затемreturn _childVC
.Они называются Property Observers :
Выдержка из: Apple Inc. «Язык программирования Swift». интерактивные книги. https://itun.es/ca/jEUH0.l
Я подозреваю, что это позволяет делать вещи, которые мы традиционно делаем с KVO, такие как привязка данных с элементами пользовательского интерфейса или побочные эффекты изменения свойства, запуска процесса синхронизации, фоновой обработки и т. Д. И т. Д. И т. Д.
источник
источник
Вы также можете использовать
didSet
переменную для установки другого значения. Это не вызывает повторного вызова наблюдателя, как указано в руководстве по свойствам . Например, это полезно, когда вы хотите ограничить значение, как показано ниже:источник
Многие хорошо написанные существующие ответы хорошо охватывают этот вопрос, но я упомяну, в некоторых деталях, дополнение, которое, я считаю, заслуживает освещения.
В
willSet
иdidSet
собственности наблюдатели могут быть использованы для вызова делегатов, например, для свойств класса, которые только когда - либо обновляемых взаимодействием с пользователем, но там , где вы хотите , чтобы избежать вызова делегата при инициализации объекта.Я процитирую комментарий Клааса с одобренным ответом на принятый ответ:
Это довольно аккуратно, так как это означает, что, например,
didSet
свойство является хорошим выбором для точки запуска делегатских обратных вызовов и функций для ваших собственных пользовательских классов.В качестве примера рассмотрим некоторый пользовательский объект пользовательского элемента управления с некоторым ключевым свойством
value
(например, положение в элементе управления рейтингом), реализованный как подклассUIView
:После чего ваши функции делегата могут быть использованы, скажем, в некотором контроллере представления для наблюдения за ключевыми изменениями в модели
CustomViewController
, так же, как вы используете встроенные функции делегатаUITextFieldDelegate
дляUITextField
объектов for (напримерtextFieldDidEndEditing(...)
).В этом простом примере используйте обратный вызов делегата из
didSet
свойства класса,value
чтобы сообщить контроллеру представления, что с одним из его выходов было связано обновление модели:Здесь
value
свойство было инкапсулировано, но обычно: в подобных ситуациях будьте осторожны, чтобы не обновлятьvalue
свойствоcustomUserControl
объекта в области действия связанной функции делегата (здесь:)didChangeValue()
в контроллере представления, иначе вы получите бесконечная рекурсия.источник
И обратите внимание, что
willSet
требуется имя параметра, чтобы обойти, с другой стороны,didSet
нет.источник
Получатель и установщик иногда слишком тяжелы для реализации, чтобы просто наблюдать правильные изменения значений. Обычно это требует дополнительной временной обработки переменных и дополнительных проверок, и вы захотите избежать даже этой крошечной работы, если напишите сотни получателей и установщиков. Эти вещи для ситуации.
источник
willSet
и поdidSet
сравнению с эквивалентным кодом сеттера? Это похоже на смелое утверждение.В вашем собственном (базовом) классе,
willSet
иdidSet
вы достаточно избыточны , так как вместо этого вы можете определить вычисляемое свойство (то есть методы get и set), которое обращается к a_propertyVariable
и выполняет желаемую предварительную и последующую обработку .Если, однако , переопределить класс , где свойство уже определено , то
willSet
иdidSet
являются полезными и не лишними!источник
Одна вещь, где
didSet
действительно удобно, это когда вы используете розетки для добавления дополнительной конфигурации.источник
Я не знаю C #, но с небольшой догадкой, я думаю, что понимаю, что
делает. Это выглядит очень похоже на то, что у вас есть в Swift, но это не то же самое: в Swift у вас нет
getFoo
иsetFoo
. Это не маленькая разница: это означает, что у вас нет базового хранилища для вашей ценности.Swift имеет сохраненные и вычисленные свойства.
Вычисленное свойство имеет
get
и может иметьset
(если оно доступно для записи). Но код в геттере и сеттере, если им действительно нужно хранить некоторые данные, должен делать это в другом свойствах. Там нет резервного хранилища.С другой стороны, сохраненное свойство имеет резервное хранилище. Но это не имеет
get
иset
. Вместо этого у него естьwillSet
иdidSet
которые вы можете использовать для наблюдения переменных изменения и, в конце концов, побочные эффекты запуска и / или изменить сохраненное значение. У вас нетwillSet
иdidSet
для вычисляемых свойств, и вам они не нужны, потому что для вычисляемых свойств вы можете использовать кодset
для управления изменениями.источник
getFoo
иsetFoo
являются простыми заполнителями для всего, что вы хотите, чтобы получатели и установщики делали. C # тоже не нуждается в них. (Я пропустил несколько синтаксических тонкостей, как я просил, прежде чем я получил доступ к компилятору.)