У нас больше не было didSet. Что теперь?
Так я научился реализовывать эквивалент onChange
в элементах управления SwiftUI для обновления других @State
переменных.
Спустя почти год после выпуска SwiftUI я решил попробовать. Я начал пачкать руки, реализовав базовые элементы управления пользовательского интерфейса (например, Slider
или TextField
) и научившись манипулировать состояниями представления.
Я быстро столкнулся с проблемой обновления @State
переменной на основе изменений другой @State
переменной.
И да, известные нам наблюдатели свойств (например, didSet
или willSet
) не работают с @State
переменными.
После некоторого исследования (которое заняло больше времени, чем я ожидал) я узнал три способа сделать это:
- Обратные вызовы элементов управления пользовательского интерфейса:
onEditingChanged
. - Связывание переменных.
- Используя
Combine
фреймворк.
Ниже я опишу конкретный простой вариант использования: проверьте, соответствует ли значение TextField
предопределенному слову, и покажите это, включив / выключив переключатель (элемент управления называется Toggle
).
Скелетный код пользовательского интерфейса:
onEditingChanged
Согласно документации разработчика Apple, этот обратный вызов доступен для трех элементов управления: TextField
, Slider
и Stepper
.
TextField: init(_:text:onEditingChanged:onCommit:)
Slider: init(value:in:onEditingChanged:)
Stepper: init(_:onIncrement:onDecrement:onEditingChanged:)
Здесь мы можем улучшить init TextField
с помощью этого параметра:
Возможным недостатком этого подхода является то, что onEditingChanged
вызывается после того, как пользователь нажимает return
клавишу на клавиатуре.
Но если вы не хотите, чтобы это происходило в режиме реального времени, это жизнеспособное решение.
Связывание переменных
Binding
- это тип оболочки свойства, который может читать и записывать значение, принадлежащее источнику истины.
Эта ссылка позволяет представлению редактировать состояние любого представления, которое зависит от этих данных.
Мы можем использовать это для имитации наблюдателей свойств из подхода UIKit (геттеры / сеттеры):
Я должен сказать, что мне не особенно нравится этот метод, так как он не выглядит чистым, чтобы объявлять привязки и иметь дело внутри раздела рендеринга.
Объединить каркас
Платформа Combine
используется для настройки обработки асинхронных событий путем комбинирования операторов обработки событий - в нашем случае для прослушивания событий изменения состояния.
В словарном запасе Combine у нас есть:
ObservableObject
- Тип объекта с издателем, который излучает до изменения объекта.ObservedObject
— объявляет зависимость от ссылочного типа, соответствующего протоколуObservableObject
. Это тип оболочки свойства, который подписывается на наблюдаемый объект и делает представление недействительным при каждом изменении наблюдаемого объекта.Published
— Тип, публикующий свойство, помеченное атрибутом.
Такой подход заставляет нас (в хорошем смысле) иметь более чистый код, извлекая бизнес-логику из представления.
Создайте модель представления:
Используйте его в желаемом виде:
Не знаю, как вы, но должен сказать, что я предпочитаю третий вариант, так как у меня больше контроля над потоком данных, а код более удобен для сопровождения. И мне это нужно в реальных случаях использования.