У нас больше не было didSet. Что теперь?

Так я научился реализовывать эквивалент onChange в элементах управления SwiftUI для обновления других @State переменных.

Спустя почти год после выпуска SwiftUI я решил попробовать. Я начал пачкать руки, реализовав базовые элементы управления пользовательского интерфейса (например, Slider или TextField) и научившись манипулировать состояниями представления.

Я быстро столкнулся с проблемой обновления @State переменной на основе изменений другой @State переменной.

И да, известные нам наблюдатели свойств (например, didSet или willSet) не работают с @State переменными.

После некоторого исследования (которое заняло больше времени, чем я ожидал) я узнал три способа сделать это:

  1. Обратные вызовы элементов управления пользовательского интерфейса: onEditingChanged.
  2. Связывание переменных.
  3. Используя 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— Тип, публикующий свойство, помеченное атрибутом.

Такой подход заставляет нас (в хорошем смысле) иметь более чистый код, извлекая бизнес-логику из представления.

Создайте модель представления:

Используйте его в желаемом виде:

Не знаю, как вы, но должен сказать, что я предпочитаю третий вариант, так как у меня больше контроля над потоком данных, а код более удобен для сопровождения. И мне это нужно в реальных случаях использования.