Ответ
@State и @Binding — это property wrappers для управления состоянием в декларативной парадигме SwiftUI, но они решают разные задачи: владение данными и их передача.
@State: Владение состоянием
- Назначение: Хранит приватное, внутреннее состояние конкретного View.
- Владение: Данные принадлежат и управляются этим View. SwiftUI создает и хранит значение.
- Область видимости: Изменяется и используется только внутри этого View (или его дочерних вью через
@Binding). - Жизненный цикл: SwiftUI уничтожает состояние, когда View удаляется.
- Инициализация: Значение устанавливается при создании View.
struct ToggleView: View {
// View ВЛАДЕЕТ этим булевым значением
@State private var isOn: Bool = false
var body: some View {
VStack {
// Локальное состояние можно изменять напрямую
Button("Переключить") {
isOn.toggle() // Изменение @State вызывает обновление View
}
// Для передачи дочернему вью используется $ для создания Binding
ChildView(isOn: $isOn)
}
}
}
@Binding: Ссылка на состояние
- Назначение: Создает двустороннюю связь (two-way binding) с состоянием, которым владеет другое (родительское) View.
- Владение: Не владеет данными, только читает и записывает значение из источника (например,
@Stateродителя). - Область видимости: Позволяет дочернему View изменять состояние родителя.
- Синтаксис: Получается через префикс
$перед свойством с@State(или другим источником данных).
struct ChildView: View {
// ChildView НЕ владеет данными, только имеет ссылку на них
@Binding var isOn: Bool
var body: some View {
Toggle("Опция", isOn: $isOn) // Toggle меняет значение в @State родителя
.padding()
}
}
Ключевая аналогия
@State— это как private переменная в классе.@Binding— это как inout параметр функции, который позволяет функции изменять значение внешней переменной.
Когда что использовать?
- Используйте
@Stateдля простых значений, принадлежащих этому View (флаги, текст поля ввода, значение слайдера). - Используйте
@Bindingкогда нужно:- Передать состояние из родительского View в дочернее для модификации.
- Создать общий контрол (кастомный Toggle, TextField), который должен работать с внешним состоянием.
- Избежать подъема состояния (state hoisting) на несколько уровней вниз, передавая
Binding.