Что делает ключевое слово SwiftUI `@State`?

Учебник SwiftUI использует @State ключевое слово для обозначения изменчивого состояния пользовательского интерфейса:

@State var showFavoritesOnly = false

Он предлагает это резюме:

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

  • Что именно означает ключевое слово?
  • Как мутирует @State переменная вызывает пересчет представления?
  • Как другие переменные неизменяемы в body добытчик?

7 ответов

Решение

@State ключевое слово @propertyWrapper, функция, недавно представленная в Swift 5.1. Как объясняется в соответствующем предложении, это своего рода оболочка значения, избегающая стандартного кода.


Примечание: @propertyWrapper ранее назывался @propertyDelegate , но это изменилось с тех пор. Смотрите этот пост для получения дополнительной информации.


Официальная документация @State содержит следующее:

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

Экземпляр State не является самим значением; это средство чтения и изменения значения. Чтобы получить доступ к базовому значению состояния, используйте его свойство value.

Поэтому, когда вы инициализируете свойство, которое помечено @State вы на самом деле не создаете свою собственную переменную, а скорее подсказываете SwiftUI создать "что-то" в фоновом режиме, которое хранит то, что вы установили, и контролирует это отныне! Твой @State var просто действует как делегат для доступа к этой оболочке.

Каждый раз, когда ваш @State переменная написана, SwiftUI будет знать, как он отслеживает это. Он также будет знать, является ли @State переменная была прочитана из View "s body, Используя эту информацию, он сможет пересчитать любой View сославшись на @State переменная в своем body после изменения этой переменной.

Позвольте мне добавить кое-что еще, если вы знаете React Native.

@State собственность очень похожа на this.state объект в React Native.

Например:

struct Foobar: some View {
    @State var username = ""
}
class Foobar extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      username: '',
    };
  }
}

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

Это хорошо объяснено на примере из видео WWDC - сессия 204 (начинается в 16:00, цитата начинается в 20:15)

Одно из особых свойств @State Переменные - это то, что SwiftUI может наблюдать, когда они читаются и пишутся. Потому что SwiftUI знает, что zoomed был прочитан в body, он знает, что рендеринг представления зависит от этого. Что означает - когда переменная изменяет структуру, будет запрашиваться body снова используя новый @State стоимость.

@State как обертка свойств также разработана и обоснована в потоке данных через Swift UI (5:38) WWDC vid. Показано, как это решает проблему, когда нам нужно непостоянное значение в неизменяемом (struct) View,

Мне нравится, как это объясняет профессор Пол Хегарти из Стэнфорда. Он сказал, что @State в основном преобразует эту переменную в указатель на какое-то логическое значение где-то еще в памяти, и там изменяется значение. Но ваша переменная - теперь указатель с @State- не изменяется, всегда указывает на это место в памяти.

Если вы нажмете в @State Вы можете видеть, что у него есть несколько добытчиков. Один с Value другой с Binding<Value>, SwiftUI, кажется, сильно зависит от реактивного программирования (и их новых Combine Framework, и поскольку мы не можем увидеть полную реализацию этих оболочек, я ожидаю, что значения, которые хранятся через @State Обертки свойств управляются CurrentValueSubject из Combine, Как следует из названия, это, по сути, хранит текущее значение, которое затем может быть использовано как связываемое свойство с помощью $ синтаксис.

Примечание. Принятый ответ правильный, но если вы пытаетесь найти более простое объяснение, которое я пробовал ниже.


Обертка свойства @State позволяет нам изменять значения внутри структуры.

Примечание . - Вы не можете изменить свойство в структуре, так как это типы значений, поэтому это не разрешено.

      struct ExampleTextView: View {

    // Declare a variable with state property wrapper
    @State private var shouldChangeText: Bool = false
    
    var body: some View {
        Text("Just an example")
            .foregroundColor(Color.white)
    }
}
  • Если вы задаетесь вопросом, должны ли мы добавить спецификатор частного доступа?

    Да, как правило, Apple рекомендует, чтобы свойство @State не использовалось совместно с другими представлениями, поскольку для этого @ObservedObject и @EnvironmentObject существуют более конкретные оболочки свойств.

  • Но если это тип значения, как его можно изменить, где он хранится?

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

Если вы думаете, что если вы сравниваете со Swift, там это делается так,

      struct Example {
    var exampleType: String
    
    mutating func changeType() {
        exampleType = "Are we allowed to do this?"
    }
}

Кредит: обратите внимание, что этот ответ вдохновлен этим сообщением https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-state-property-wrapper .

Если вы знаете о разработке на C# и Windows. @State похоже, если не то же самое, что x:Bind или Binding.. По коллекции похоже, если не так, как ObservableCollection.

Как сказал Фредпи, SwiftUI содержит список обновлений для vars с @State делегат собственности.

Другие вопросы по тегам