【问题标题】:Updating Member of an Array更新数组的成员
【发布时间】:2020-09-30 13:57:23
【问题描述】:

这里是新手。 我的问题简化了:

我有一个由 2 个字符串组成的 Person 结构 - 名字和姓氏。 包含几个人的初始数组(例如“Bob”“Smith”、“Joe”“Johnson”等) 显示每个成员的列表视图。

单击列表中的一行会显示详细视图 - 称之为“个人卡片”视图 - 显示名字和姓氏。

然后我有一个模态视图来编辑这些变量。 目前模态框上的保存按钮仅关闭模态框。但是,因为我在模式视图上使用绑定到“人员卡”视图上的值,所以当模式关闭时,“人员卡”视图会使用更改的数据进行更新。

列表视图仍然显示原始值而不是更新的数据(如我所料)。我知道我必须将 as 方法添加到保存功能,但我不确定是什么。我知道如何插入和追加到数组,但我找不到更新数组方法。

仅供参考 - 我使用的数据模型是 ObservableObject 类的“存储”实例。我在每个视图上将该变量声明为 EnvironmentObject。

这里是要求的代码:

struct PatientData: Identifiable
{
    let id = UUID()

    var patientName: String
    var age: String

}



let patientDataArray: [PatientData] = 

[  
    PatientData(patientName: "Charles Brown", age: "68"),
    PatientData(patientName: "Jim Morrison", age: "36"),
]



final class PatientDataController: ObservableObject
{
@Published var patients = patientDataArray
{



struct PatientList: View
{
    @EnvironmentObject var patientDataController: PatientDataController
    @State private var showModalSheet = false

    var body: some View
    {
        NavigationView
        {
            List
            {
                ForEach(patientDataController.patients)
                { patientData in    NavigationLink(destination: PatientInfoCard(patientData: patientData))
                { PatientListCell(patientData: patientData) }
                }
                .onMove(perform: move)
                .onDelete(perform: delete)

                .navigationBarTitle(Text("Patient List"))
            }



struct PatientInfoCard: View
{
    @EnvironmentObject var patientDataController: PatientDataController

    @State var patientData: PatientData
    @State private var showModalSheet = false

    var body: some View
    {
        VStack(alignment: .leading, spacing: 8)
        {  // Change to patientDataArray???
            Text(patientData.patientName)
                .font(.largeTitle)
            BasicInfo(patientData: patientData)
            Spacer()
                .frame(minWidth: 0, maxWidth: .infinity)
        }
        .padding()

        // Can't push Edit button more than once
        .navigationBarItems(trailing: Button(action:
            {self.showModalSheet = true})
                {Text("Edit")})
            .sheet(isPresented: $showModalSheet)
        {
            EditPatientModal(patientData: self.$patientData, showModalSheet: self.$showModalSheet)
                .environmentObject(self.patientDataController)

        }
    }
}



struct EditPatientModal: View
{
    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject var patientDataController: PatientDataController
    @Binding var patientData: PatientData
    @Binding var showModalSheet: Bool

    var body: some View
    {
        NavigationView
        {
            VStack(alignment: .leading)
            {
                Text("Name")
                    .font(.headline)
                TextField("enter name", text: $patientData.patientName)


                Text("Age")
                    .font(.headline)
                TextField("enter age", text: $patientData.age)

            }
            .navigationBarTitle(Text("Edit Patient"), displayMode: .inline)
            .navigationBarItems(
                leading: Button("Cancel")
                    { self.cancel() },
                trailing: Button("Save")
                    { self.save() } )
        }
    }

    private func save()
    {

        self.presentationMode.wrappedValue.dismiss()
    }

这是我更新的代码:

class PatientData: ObservableObject, Identifiable
{
    let id = UUID()

    @Published var patientName = ""
    @Published var age = ""

    init(patientName: String, age: String)
    {
        self.patientName = patientName
        self.age = age

    }
}



let patientDataArray: [PatientData] =
[
    PatientData(patientName: "Charles Brown", age: "68"),
    PatientData(patientName: "Jim Morrison", age: "36")    
]



final class PatientDataController: ObservableObject
{
    @Published var patients = patientDataArray
}



struct PatientList: View
{
    @EnvironmentObject var patientDataController: PatientDataController
    @EnvironmentObject var patientData: PatientData
    @State private var showModalSheet = false

    var body: some View
    {
        NavigationView
        {
            List
            {
                ForEach(self.patientDataController.patients.indices)
                { idx in
                NavigationLink(destination: PatientInfoCard(patientData: self.$patientDataController.patients[idx]))

 /*Cannot convert value of type 'Binding<PatientData>' to expected argument type 'PatientData'*/ <-- My one error message; in NavigationLink

                { PatientListCell(patientData: self.$patientDataController.patients[idx]) }
                }
                .onMove(perform: move)
                .onDelete(perform: delete)

                .navigationBarTitle(Text("Patient List"))
            }
        .navigationBarItems(leading: EditButton())



struct PatientInfoCard: View
{
    @EnvironmentObject var patientDataController: PatientDataController

    @Binding var patientData: PatientData
    @State private var showModalSheet = false

    var body: some View
    {
        VStack(alignment: .leading, spacing: 8)
        {  
            Text(patientData.patientName)
                .font(.largeTitle)
            BasicInfo(patientData: patientData)
            Spacer()
                .frame(minWidth: 0, maxWidth: .infinity)
        }
        .padding()
        .navigationBarItems(trailing: Button(action:
            {self.showModalSheet = true})
                {Text("Edit")})
            .sheet(isPresented: $showModalSheet)
        {
            EditPatientModal(patientData: self.$patientData, showModalSheet: self.$showModalSheet)
                .environmentObject(self.patientDataController)

        }
    }
}


struct BasicInfo: View
{
    @EnvironmentObject var patientDataController: PatientDataController

    @State var patientData: PatientData

    var patientDataIndex: Int
    {
        patientDataController.patients.firstIndex(where: { $0.id == patientData.id })!
    }

    var body: some View
    {
        VStack(alignment: .leading, spacing: 8)
        {

            Text("Age:")
                .font(.headline)
            Text(patientData.age)
                .font(.subheadline)
                .foregroundColor(.secondary)

        }
    }
}



struct EditPatientModal: View
{
    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject var patientDataController: PatientDataController

    @Binding var patientData: PatientData
    @Binding var showModalSheet: Bool

    var body: some View
    {
        NavigationView
        {
            VStack(alignment: .leading)
            {
                Text("Name")
                    .font(.headline)
                TextField("enter name", text: $patientData.patientName)


                Text("Age")
                    .font(.headline)
                TextField("enter age", text: $patientData.age)

            }
            .navigationBarTitle(Text("Edit Patient"), displayMode: .inline)
            .navigationBarItems(
                leading: Button("Cancel")
                    { self.cancel() },
                trailing: Button("Save")
                    { self.save() } )
        }
    }

    private func save()
    {

        self.presentationMode.wrappedValue.dismiss()
    }

【问题讨论】:

标签: ios arrays swift iphone swiftui


【解决方案1】:

您的代码中缺少两件事。

您的结构必须是ObservableObject,否则发生的任何更改都不会生效,并且为了使其成为ObservableObject,它必须是一个类,所以首先要更改:

class PatientData: ObservableObject, Identifiable
{
    let id = UUID()
    @Published var patientName: String
    @Published var age: String

    init(patientName: String, age: String) {
        self.patientName = patientName
        self.age = age
    }
}

我知道您有一个正在发布的 environmentObject,但它只是发布对数组的更改,这意味着添加或删除项目而不是单个 patientData 对象。

要更改的第二件事是在您的forEach loop 中,您需要将Patient 作为Bind 传递,为此您必须遍历索引,然后通过Bind 访问数据

NavigationView
        {
            if(self.patientDataController.patients.count > 0) {
                    List {
                        ForEach(self.patientDataController.patients.enumerated().map({$0}), id:\.element.id) { idx, patient in
                            NavigationLink(destination: PatientInfoCard(patientData: self.$patientDataController.patients[idx])) {
                                Text(patient.patientName)
                            }
                        }
                    }
                    .navigationBarItems(leading: EditButton())
                } else {
                    Text("List is empty")
                }
        }

如果这不起作用,请告诉我们

【讨论】:

  • 谢谢。我注意到我没有在代码中添加“PatientInfoCard”结构(或“PersonCard”,因为我在问题的简短描述中称它为“PersonCard”)。我目前正在工作,所以当我回到家时,我会添加该代码并进行 2 项建议的更改。我不知道声明变量的结构也必须是一个 ObservableObject(因此也是一个类)。我认为只有这些变量的数组必须是。
  • 完全不用担心,我注意到了这一点,但我认为这不会有所作为,但如果我提出的建议不起作用,请更新代码,我应该能够提供帮助。跨度>
  • 注意:我在我的代码中添加了“PatientInfoCard”结构 - 但不确定它是否重要。
  • 知道了,确保做出我建议的更改,如果不起作用,我会查看您的 PatientInfoCard
  • 所以我在下面发布的更新代码中有一条错误消息。
猜你喜欢
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
  • 2020-10-07
  • 1970-01-01
  • 2017-10-09
  • 1970-01-01
  • 2017-01-14
  • 1970-01-01
相关资源
最近更新 更多