更新模型时不会更新详细视图(使用列表)SwiftUI

Detail View is not updated when the model is updated (Using List) SwiftUI

我正在使用 List 在主视图中显示模型。当我在详细视图中更新模型时,它不会在详细视图中更新。

当我不使用 List 时,详细视图会更新。 List 我错过了什么?


struct Person: Identifiable {
  var id: UUID
  var name: String
}

class PersonModel: ObservableObject {
  @Published var persons: [Person] = [Person(id: UUID(), name: "Ege")]
}

struct PersonListView: View {
  
  @StateObject private var personModel = PersonModel()
  
  var body: some View {
    NavigationView {
      List {
        ForEach(personModel.persons) { person in
          NavigationLink(destination: PersonDetailView(person: person).environmentObject(personModel)) {
            Text(person.name)
          }
        }
      }
      .navigationTitle("Persons")
    }
  }
}

struct PersonDetailView: View {
  
  let person: Person
  @EnvironmentObject var personModel: PersonModel
  
  var body: some View {
    VStack {
      Text(person.name)
      
      Button(action: {
        let personIndex = personModel.persons.firstIndex(where: { [=10=].id == person.id })!
        personModel.persons[personIndex].name = "Updated Name"
      }) {
        Text("Update")
      }
    }
    .navigationTitle("Person Detail")
  }
}

我用于 List 的解决方法:

示例代码:

//1
private func binding(for person: Person) -> Binding<Person> {
  let personIndex = personModel.persons.firstIndex(where: { [=11=].id == person.id }) ?? 0
  return $personModel.persons[personIndex]
}
//2
NavigationLink(destination: PersonDetailView(person: binding(for: person)))
//3
@Binding var person: Person //DetailView

编辑

您可以发送手动更改,但您需要使用 class 而不是模型的结构。 像这样

Button(action: {
    if let personIndex = personModel.persons.firstIndex(where: { [=10=].id == person.id }) { //<==Here
        personModel.persons[personIndex].name = "Updated Name"
        personModel.objectWillChange.send() //<==Here
    }
    
})

可能的解决方案是更新数据并将元素重新分配给数组。

struct PersonDetailView: View {
    
    let person: Person
    @EnvironmentObject var personModel: PersonModel
    
    var body: some View {
        VStack {
            Text(person.name)
            
            Button(action: {
                if let personIndex = personModel.persons.firstIndex(where: { [=11=].id == person.id }) { //<==Here
                    personModel.persons[personIndex].name = "Updated Name"
                    personModel.persons[personIndex] = personModel.persons[personIndex]
                }
                
            }) {
                Text("Update")
            }
        }
        .navigationTitle("Person Detail")
    }
}

并使用class

class Person: Identifiable {
    var id: UUID
    var name: String
    
    init(id: UUID, name: String) {
        self.id = id
        self.name = name
    }
}

在我看来,尽管您的变通办法确实有效,但您想首先了解发生了什么以及为什么需要变通办法。

当您更新 @Published var persons: [Person] 数组的值时,您的详细视图将按照您的预期重新呈现。但是您告诉您的视图打印 var person: Person 结构的 name 值,该值没有改变。还是和刚创建视图时一样。

如果你更换

Text(person.name)

Text(personModel.persons.first(where: { [=11=].id == person.id } )!.name)

它会按照您的预期进行更新,因为您正在为文本视图提供新版本 personname 值,该值是从您刚刚创建的实际 PersonModel 中提取的已更新。

所以 List 的参与似乎不是问题,这就是为什么我没有直接回答你的问题“List 我错过了什么?”。希望它能有所帮助!

此问题似乎已在 Xcode 13 Beta 中修复。