В чем разница между property wrappers @State и @Binding в SwiftUI?

«В чем разница между property wrappers @State и @Binding в SwiftUI?» — вопрос из категории SwiftUI, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

@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.