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

时间:2021-02-10 16:57:28

标签: swift swiftui combine swiftui-list

我使用 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: { $0.id == person.id })!
        personModel.persons[personIndex].name = "Updated Name"
      }) {
        Text("Update")
      }
    }
    .navigationTitle("Person Detail")
  }
}

我用于 List 的解决方法:

  • 为 NavigationLink 使用自定义绑定函数。

示例代码:

//1
private func binding(for person: Person) -> Binding<Person> {
  let personIndex = personModel.persons.firstIndex(where: { $0.id == person.id }) ?? 0
  return $personModel.persons[personIndex]
}
//2
NavigationLink(destination: PersonDetailView(person: binding(for: person)))
//3
@Binding var person: Person //DetailView
  • 在详细信息视图中使用另一个 @State onAppear 方法中的模型。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

在我看来,虽然您的解决方法肯定有效,但您首先想知道发生了什么以及为什么需要解决方法。

当您更新 @Published var persons: [Person] 数组的值时,您的详细信息视图会按照您的预期重新呈现。但是您告诉您的视图打印未更改的 name 结构的 var person: Person 值。它仍然与最初创建视图时相同。

如果更换

Text(person.name)

Text(personModel.persons.first(where: { $0.id == person.id } )!.name)

它会按照您的预期更新,因为您正在为 Text 视图提供从您刚刚更新的实际 name 中提取的新版本 personPersonModel 值。

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

答案 2 :(得分:-2)

编辑

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

Button(action: {
    if let personIndex = personModel.persons.firstIndex(where: { $0.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: { $0.id == person.id }) { //<==Here
                    personModel.persons[personIndex].name = "Updated Name"
                    personModel.persons[personIndex] = personModel.persons[personIndex]
                }
                
            }) {
                Text("Update")
            }
        }
        .navigationTitle("Person Detail")
    }
}

并使用类

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