Инициализируйте `@ State`ful структуру с` @ Binding` в SwiftUI - PullRequest
0 голосов
/ 20 апреля 2020

У меня есть приложение, в котором две разные структуры зависят от отдельного фрагмента данных, и когда я изменяю эти данные, обе структуры должны знать об этом изменении. Я думаю, что мог бы решить проблему с помощью ре-факторинга или с @EnvironmentObject, но я хочу понять, почему этот код не работает. В SceneDelegate.swift в проекте iOS установите contentView с помощью let contentView = StateTestTopView(), а затем создайте файл с таким кодом:

import SwiftUI

struct Person { @Binding var name: String }
struct Character { @Binding var name: String }

struct StateTestTopView: View {
  @State private var name: String = "Bilbo"

  var body: some View {
    VStack {
      StateTestPickerView(name: $name)
      Spacer()
      Text("Global name selection is \(name)").font(.title)
    }
  }
}

struct StateTestPickerView: View {
  @Binding var name: String
  @State private var person: Person
  @State private var character: Character
  init(name: Binding<String>) {
    self._name = name
    self._person = State(initialValue: Person(name: name))
    self._character = State(initialValue: Character(name: name))
  }
  var body: some View {
    VStack{
      Picker(selection: $name,
             label: Text(verbatim: "Selected name: \(name)")) {
              ForEach(["Sam", "Gandalf", "Gollum"], id: \.self) { name in
                Text(name)
              }
      }
      Text("You picked \(name)")
      ShowPersonAndCharacter(
        person: self.$person, character: self.$character)
    }
  }
}

struct ShowPersonAndCharacter: View {
  @Binding var person: Person
  @Binding var character: Character

  var body: some View {
    Text("\(person.name) is great! \(character.name) is the same person!")
  }
}

Проблема в том, что ShowPersonAndCharacter имеет @Binding s до структур Person и Character, но связанные структуры не обновляются при изменении базовых данных. Я подозреваю, что проблема в инициализаторе представления Picker:

  @Binding var name: String
  @State private var person: Person
  @State private var character: Character
  init(name: Binding<String>) {
    self._name = name
    self._person = State(initialValue: Person(name: name))
    self._character = State(initialValue: Character(name: name))
  }

Здесь я думаю, что структуры Person и Character создаются с моментальным снимком связанной строки и фактически не получают привязку. Я не уверен, как это исправить, или даже если мой диагноз удаленно верен.

Есть идеи?

Спасибо за ваше время!

1 Ответ

1 голос
/ 20 апреля 2020

Я согласен с @Asperi, Binding предназначен для использования в видах, а не в моделях. На самом деле в этом случае вам не нужно, чтобы ваша модель имела привязки вообще. Поскольку @Binding var name: String является привязкой в ​​StateTestPickerView, она обновит представление самостоятельно, как только обновится. Смотрите следующую модификацию вашего кода. Это прекрасно работает для меня:

struct Person { var name: String }
struct Character { var name: String }

struct StateTestTopView: View {
    @State private var name: String = "Bilbo"

    var body: some View {
        VStack {
            StateTestPickerView(name: $name)
            Spacer()
            Text("Global name selection is \(name)").font(.title)
        }
    }
}

struct StateTestPickerView: View {
    @Binding var name: String

    var body: some View {
        VStack{
            Picker(selection: $name,
                   label: Text(verbatim: "Selected name: \(name)")) {
                    ForEach(["Sam", "Gandalf", "Gollum"], id: \.self) { name in
                        Text(name)
                    }
            }
            Text("You picked \(name)")
            ShowPersonAndCharacter(person: Person(name: self.name),
                                   character: Character(name: self.name))
        }
    }
}

struct ShowPersonAndCharacter: View {
    var person: Person
    var character: Character

    var body: some View {
        Text("\(person.name) is great! \(character.name) is the same person!")
    }
}

Обратите внимание, что оболочка свойства Binding была удалена из моделей. Кроме того, StateTestPickerView напрямую вызывает представление, используя привязку имени в следующем коде: ShowPersonAndCharacter(person: Person(name: self.name), character: Character(name: self.name))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...