SwiftUI @Binding не обновляет вид
У меня есть простой интерфейс master/detail, где детальный вид изменяет элемент в массиве. Используя ниже, модель обновляется должным образом, но SwiftUI не обновляет представление, чтобы отразить изменение.
Модель:
struct ProduceItem: Identifiable {
let id = UUID()
let name: String
var inventory: Int
}
final class ItemStore: BindableObject {
var willChange = PassthroughSubject<Void, Never>()
var items: [ProduceItem] { willSet { willChange.send() } }
init(_ items: [ProduceItem]) {
self.items = items
}
}
Главное представление, которое отображает список ProduceItems (ItemStore вставляется в среду в SceneDelegate):
struct ItemList: View {
@EnvironmentObject var itemStore: ItemStore
var body: some View {
NavigationView {
List(itemStore.items.indices) { index in
NavigationLink(destination: ItemDetail(item: self.$itemStore.items[index])) {
VStack(alignment: .leading) {
Text(self.itemStore.items[index].name)
Text("\(self.itemStore.items[index].inventory)")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
.navigationBarTitle("Items")
}
}
}
Подробный вид, позволяющий изменить стоимость инвентаря предмета:
struct ItemDetail: View {
@Binding var item: ProduceItem
var body: some View {
NavigationView {
Stepper(value: $item.inventory) {
Text("Inventory is \(item.inventory)")
}
.padding()
.navigationBarTitle(item.name)
}
}
}
Нажатие на степпер в представлении ItemDetail изменяет элемент в магазине, но текст степпера не изменяется. Возвращение к списку подтверждает, что модель была изменена. Также я подтвердил, что магазин звонит willChange.send()
его издателю. Я бы предположил, что send()
вызов обновляет ItemStore в среде и подробном представлении @Binding
свойство должно быть уведомлено об изменении и обновить отображение (но это не так).
Я попытался изменить свойство item ItemDetail для использования @State
:
@State var item: ProduceItem = ProduceItem(name: "Plums", inventory: 7)
В этом случае модель элемента обновляется при использовании степпера, а представление обновляется, отображая обновленный инвентарь. Может кто-нибудь объяснить, почему с помощью @Binding
свойство не обновляет интерфейс, но локально @State
собственность делает?
1 ответ
Здесь у вас есть обходной путь. Используйте индекс вместо элемента при вызове ItemDetail. А внутри ItemDetail вы используете @EnvironmentObject
,
struct ItemList: View {
@EnvironmentObject var itemStore: ItemStore
var body: some View {
NavigationView {
List(itemStore.items.indices) { index in
NavigationLink(destination: ItemDetail(idx: index)) {
VStack(alignment: .leading) {
Text(self.itemStore.items[index].name)
Text("\(self.itemStore.items[index].inventory)")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
.navigationBarTitle("Items")
}
}
}
struct ItemDetail: View {
@EnvironmentObject var itemStore: ItemStore
let idx: Int
var body: some View {
NavigationView {
Stepper(value: $itemStore.items[idx].inventory) {
Text("Inventory is \(self.itemStore.items[idx].inventory)")
}
.padding()
.navigationBarTitle(itemStore.items[idx].name)
}
}
}