Tehnografi.com - Технологические новости, обзоры и советы

Объяснение оболочки свойства @State в SwiftUI

Следующая статья поможет вам: Объяснение оболочки свойства @State в SwiftUI

Вернуться в блог

С помощью @State вы сообщаете SwiftUI, что представление теперь зависит от некоторого состояния. Если состояние изменится, изменится и пользовательский интерфейс. Это основной принцип SwiftUI: данные управляют пользовательским интерфейсом. Но как это работает?

В этом руководстве по разработке приложений мы обсудим, как использовать @State со SwiftUI. Мы создадим простое представление, которое обновляет текст по мере ввода его в текстовое поле. И, конечно же, мы также деконструируем то, что происходит за кулисами.

Вот во что мы вникнем:

  • Как @State работает в SwiftUI и для чего он нужен?
  • Такие принципы, как пользовательский интерфейс дисков данных и единый источник достоверной информации.
  • Что такое оболочки свойств и как они работают?
  • Как подключить TextField к @State с помощью привязки
  • Ваши новые друзья $name и _name

Перво-наперво. В SwiftUI @State — это одна из многих оболочек свойств, которые вы можете использовать. Но что такое оболочка свойств?

Обертка свойства «обертывает» свойство (или так ли?) и дополняет его дополнительным поведением. По сути, оболочка свойства добавляет к свойству массу кода – и это дает свойству сверхспособности. Теперь вы можете делать больше с недвижимостью.

Вы можете сравнить оболочки свойств со слабыми или @IBOutlet. Слабый атрибут меняет способ сохранения свойства в памяти; Атрибут @IBOutlet делает свойство доступным для подключения в Interface Builder. Однако оболочки свойств более мощны и глубоко интегрируются со SwiftUI.

Авторы Note: Мне нравится думать об обертках от собственности как о буррито. Видите ли, начинка буррито — это просто сальса, мясо, фасоль и гуакамоле без тортильи. С таким же успехом это может быть перец чили кон карне без «обертки». Благодаря лепешке буррито можно взять в руки и съесть. Тортилья оборачивает начинку, позволяя вам делать больше, точно так же, как @State оборачивает простое свойство, делая его больше.

Основной принцип SwiftUI заключается в том, что данные управляют пользовательским интерфейсом. Всякий раз, когда некоторые данные в вашем приложении изменяются, пользовательский интерфейс (UI), который представляет (и наблюдает) эти данные, также меняется. Вы никогда не манипулируете и не изменяете пользовательский интерфейс напрямую; вы меняете данные, и пользовательский интерфейс вашего приложения впоследствии обновляется.

Вы можете использовать слово «состояние», когда говорите о данных. Например, когда «состояние» вашего друга злится, его лицо меняется с нейтрального на нахмуренное или совершенно безумное. Если эмоции — это данные, они могут быть представлены разными состояниями, и это меняет выражение лица вашего друга.

SwiftUI основан на идее, что каждое состояние приводит к разным, но детерминированным изменениям пользовательского интерфейса. Сделав данные движущей силой пользовательского интерфейса, SwiftUI может эффективно создавать и обновлять пользовательские интерфейсы. Кроме того, таким образом легче рассуждать о своем коде, особенно по сравнению с обычным хаосом в контроллере представления.

Давайте посмотрим на некоторый код:

структура ContentView: Просмотр
{
имя переменной: String = «Боб и Алиса»

var body: some View {
Text(“Здравствуйте, \(имя)!”)
}
}

В приведенном выше коде SwiftUI мы определили простое текстовое представление, которое будет отображать приветствие на основе имени свойства типа String. Как есть, это представление всегда будет одним и тем же, поскольку состояние представления статично. Это не меняется.

Теперь предположим, что мы хотим изменить приветствие на основе ввода текста. Мы меняем код на этот:

структура ContentView: Просмотр
{
имя переменной: String = «Боб и Алиса»

var body: some View {
ВСтек {
Text(“Здравствуйте, \(имя)!”)
TextField(“Имя”, текст: )
}
}
}

В приведенном выше коде мы добавили представление TextField под представлением Text. Мы по-прежнему создаем приветствие на основе свойства name. Но представления в SwiftUI неизменяемы; вы не можете изменить их свойства. Как мы можем сделать приветствие динамичным и использовать текст в TextField для изменения пользовательского интерфейса?

Вот тут-то и приходит на помощь @State. Мы можем добавить эту оболочку свойства к name, и тем самым мы сообщим SwiftUI, что представление теперь зависит от состояния свойства name.

SwiftUI теперь будет управлять хранением этого свойства, поскольку мы объявили его как состояние. Всякий раз, когда изменяется свойство name, пользовательский интерфейс (т. е. представление) также должен обновляться.

Мы также привяжем TextField к свойству name, чтобы содержимое текстового поля записывалось в имя. Эта привязка соединяет текстовое поле и данные.

Проверь это:

структура ContentView: Просмотр
{
Имя частной переменной @State: String = «Боб и Алиса»

var body: some View {
ВСтек {
Text(“Здравствуйте, \(имя)!”)
TextField («Имя», текст: $name)
}
}
}

В приведенном выше коде мы внесли несколько важных изменений:

  1. К свойству name добавляется оболочка свойства @State, и свойство становится частным. Представление теперь зависит от состояния имени и обновляется, когда имя меняется.
  2. Текстовый параметр TextField получает аргумент $name, знак доллара $, за которым следует имя свойства, т. е. имя. Это создает привязку между текстовым полем и свойством имени.

Вот как это выглядит в приложении на iPhone Simulator:

Быстрый Note: Вы используете @State для «локального» или «внутреннего» состояния представления, то есть данных, которые не покидают представление. Вы можете использовать @ObservedObject и другие для внешнего состояния. Поскольку @State является локальным, свойство обычно помечается как частное. Это подчеркивает, что государство не покидает поля зрения.

По сути, здесь действуют два основных принципа:

  1. Свойство @State делает представление зависимым от состояния имени, поэтому при изменении текстового значения имени представление обновляется, чтобы отобразить это изменение.
  2. TextField получает привязку к свойству name, которая позволяет текстовому полю изменять текстовое значение name. О креплениях позже.

Потрясающий! Давайте посмотрим поближе.

Как и большинство вещей SwiftUI, работа с состоянием на самом деле представляет собой множество движущихся частей, работающих вместе в тандеме. Несколько принципов, которые следует учитывать:

  • В SwiftUI данные управляют пользовательским интерфейсом
  • Представления неизменны; вы не можете просто изменить свойство имени
  • @State делает представление зависимым от состояния; о стоимости недвижимости
  • С помощью @State мы сообщаем SwiftUI управлять хранилищем свойства за нас.
  • Когда значение свойства (состояние) изменяется, представление также должно обновиться.

Это почти похоже на волшебство! Но это реально, никакого волшебства. Как и в случае с Волшебником страны Оз, за ​​кулисами стоит крошечный человечек, тянущий веревки и провода. И поскольку это реально, мы можем обнаружить и понять, как это работает.

Когда вы аннотируете свойство name с помощью оболочки свойства @State, SwiftUI синтезирует 2 дополнительных свойства: $name и _name. Если ваше свойство называется cookie, остальные свойства называются $cookies и _cookies и так далее.

Теперь у вас есть 3 объекта недвижимости:

  1. name — это (фактическое) завернутое значение свойства, т. е. «Боб и Алиса».
  2. _name — это сама структура-оболочка свойства, которая для @State — это State
  3. $name — это прогнозируемое значение, предоставляющее дополнительные функции, которые для @State являются привязкой.

Эти дополнительные свойства создаются для вас, когда вы добавляете к свойству атрибут @State. Это 3 по цене 1! Но почему?

Одна из целей SwiftUI — сделать создание пользовательских интерфейсов более продуктивным. SwiftUI делает это путем формализации отношений между данными (т. е. состоянием) и пользовательским интерфейсом.

Вместо того, чтобы позволять вам кодировать все самостоятельно, как в случае с раскадровками, теперь вы получаете кучу готовых инструментов, таких как @State. Именно для этого и нужны фреймворки: обеспечивать функциональность, чтобы вам не приходилось писать код самостоятельно.

Обертки свойств — это механизм, позволяющий добавлять функциональность свойствам, например управлять хранением состояния. Обертка свойства «добавляет код» к свойству. Это автоматически синтезируется; SwiftUI создаст его за вас, поэтому вам не придется это делать.

Какой код он добавляет? Структура State, а также $name и _name. Вы по-прежнему получаете доступ к значению имени, а также ко всему прочему. Эта «обертка» (начинки буррито!) позволяет вам делать со свойством больше, например реагировать на изменения состояния.

Учтите, что _name.wrappedValue равно name, а _name.projectedValue равно $name. Это структура State, которую вы «получаете» через @State, которая управляет хранением, извлечением и обновлением свойства простого имени. Аккуратный!

Вы можете просмотреть официальную документацию по структуре State и убедиться, что на самом деле это вовсе не волшебство. Вы можете увидеть завернутое значение, проецируемое значение с помощью Binding и даже способ установить начальное значение для свойства @State.

До сих пор мы обсуждали только то, как @State оборачивает свойство и как SwiftUI впоследствии управляет хранением этого свойства. Однако у государственной структуры есть еще один интересный компонент: привязка.

До сих пор мы обсуждали только то, как @State оборачивает свойство и как SwiftUI впоследствии управляет хранением этого свойства. Однако у государственной структуры есть еще один интересный компонент: привязка.

Как следует из названия, привязка позволяет вам привязать значение к чему-то другому. В нашем примере это TextField. Это не может быть проще: вы предоставляете $name в TextField, и всякий раз, когда текст в TextField изменяется, изменяется и значение свойства name.

Вот соответствующий код еще раз:

структура ContentView: Просмотр
{
Имя частной переменной @State: String = «Боб и Алиса»

var body: some View {
ВСтек {
Text(“Здравствуйте, \(имя)!”)
TextField («Имя», текст: $name)
}
}
}

Видите этот бит TextField(“Name”, text: $name)? Это «подключит» свойство name к текстовому полю. При изменении текста в текстовом поле изменяется и строковое значение свойства name.

Если мы внимательно посмотрим на $name, то увидим, что его тип — Binding. Эта структура Binding, которая сама по себе является оболочкой свойства, создает двустороннее соединение между свойством, в котором хранятся данные, и представлением, которое отображает и изменяет эти данные.

С @State вы действительно получаете 2 оболочки свойств по цене 1. Есть State, который управляет хранением данных. И есть Binding, который создает соединение между хранилищем данных и представлением.

Это заставляет задуматься: управляет ли TextField своим собственным состоянием? Что касается значения в текстовом поле, нет! Привязка соединяет TextField с некоторым состоянием. В нашем случае это свойство name.

Это подводит нас к последнему важному принципу работы со SwiftUI: единому источнику истины. Вы часто будете сталкиваться с этим термином при работе со SwiftUI.

Источник истины — это просто «одно место», где хранится состояние. Поскольку представления SwiftUI зависят от состояния, вы не можете иметь две копии одних и тех же данных. Если есть 2 копии, какая из них будет использоваться для обновления представления? Нет, у вас может быть только один источник истины.

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

Авторы Note: @Binding и оболочки свойств, такие как @ObservedObject, — это нечто большее, чем мы сейчас обсуждаем. Узнайте больше в разделах @ObservedObject и Friends в SwiftUI и в разделе Работа с @Binding в SwiftUI.

Пффф! Кто знал, сколько сложностей скрывается за простым атрибутом вроде @State. Знаешь, что самое крутое? Вы можете забыть все, что вы только что узнали, и просто работать с @State таким, какой он есть.

Когда свойство, помеченное @State, изменяется, представление также обновляется. И вы даже можете привязать это свойство к какому-либо другому компоненту пользовательского интерфейса, например TextField, и заставить его волшебным образом обновляться при изменении текстового поля. Хоть это и не волшебство, но такое ощущение. Потрясающий!