Ниже приведен пример из более сложного приложения. RootModel
имеет массив Items
, а каждый Item
имеет свойство text
. Мой пользовательский интерфейс использует NavigationView
to pu sh представлений root модели, элемента и затем текста.
В приведенном ниже примере кода, если я создаю элемент и редактирую его текст, представление TextEditor
не отображается повторно. Если я возвращаюсь назад, я вижу, что модель изменилась правильно. Почему он не рендерится повторно, когда я нажимаю кнопку «Случайно изменить его» в представлении TextEditor
?
Я не хочу превращать все в ObservableObject
. Я согласен с этим для root объектов, но Swift прекрасно работает с неизменяемыми типами значений и протоколами, и я не хочу отказываться от этого, чтобы сделать каждую часть моей модели изменяемым объектом.
struct Item {
var text: String = ""
}
class RootModel: ObservableObject {
@Published var items: [Item] = []
}
struct ContentView: View {
@ObservedObject var model: RootModel
@State private var isEditItemActive = false
/// Add a state var to say which item we're editing.
@State private var editingIndex: Int = -1
var body: some View {
NavigationView {
VStack {
Text("View of RootModel object")
HStack {
Text("Items")
Spacer()
Button(action: self.addItem) {
Text("Add")
}
}
ForEach(model.items.indices, id: \.self) { idx in
HStack {
Text("Item: \(self.model.items[idx].text)")
Image(systemName: "chevron.right")
}.onTapGesture {
self.editItem(index: idx)
}
}
Button(action: self.deleteAllItems) {
Text("Delete all items")
}
NavigationLink(destination: EditItemView(array: $model.items, index: $editingIndex),
isActive: $isEditItemActive) {
EmptyView()
}
Spacer()
}
.padding()
.navigationBarTitle("Root", displayMode: .inline)
}
}
private func deleteAllItems() {
model.items.removeAll()
}
private func addItem() {
let num = Int.random(in: 10000...20000)
let newItem = Item(text: "\(num)")
model.items.append(newItem)
editItem(index: model.items.count-1)
}
private func editItem(index: Int) {
print("edit \(index)")
editingIndex = index
isEditItemActive = true
}
}
struct EditItemView: View {
@Binding var array: [Item]
@Binding var index: Int
@State private var isTextEditorPushed = false
var body: some View {
VStack {
Text("Editing item")
Text("Text: \(array[index].text)")
Button(action: self.editText) {
Text("Edit item.text")
}
NavigationLink(destination: TextEditor(text: $array[index].text),
isActive: $isTextEditorPushed) {
EmptyView()
}
Spacer()
}
}
private func editText() {
isTextEditorPushed = true
}
}
struct TextEditor: View {
@Binding var text: String
var body: some View {
VStack {
Text("Editing item.text:")
Text("Text: \(text)")
Button(action: self.changeText) {
Text("Randomly change it")
}
}
}
private func changeText() {
let n = Int.random(in: 10000...20000)
print("changeText: \(n)")
text = "\(n)"
}
}