【问题标题】:SwiftUI - How to append data to nested struct?SwiftUI - 如何将数据附加到嵌套结构?
【发布时间】:2021-01-23 09:43:43
【问题描述】:

我有一个连接到结构的学生类 - 详细信息。其中有一个嵌套结构 - 主题。我知道如何附加到普通结构或类,但我在尝试附加到嵌套结构时遇到了困难。我所拥有的是一个表格,其中询问学生的姓名和科目数量,之后他们必须输入科目名称和等级。然后,按 Toolbar items/NavigationBarItems 中的保存按钮。

class Students: ObservableObject {
    @Published var details = [Details]()
}

struct Details: Identifiable {
    let id = UUID()
    let name: String
    
    struct Subjects: Identifiable {
        let id = UUID()
        let name: String
        let grade: String
    }
    
    let subjects: [Subjects]
}

视图类:

import SwiftUI

struct TestStudentView: View {
    @StateObject var students = Students()
    @State private var name = ""
    @State private var numberOfSubjects = ""
    @State private var subject = [String](repeating: "", count: 10)
    @State private var grade = [String](repeating: "", count: 10)
    @State private var details = [Details.Subjects]()
    var body: some View {
        NavigationView {
            Group {
                Form {
                    Section(header: Text("Student details")) {
                        TextField("Name", text: $name)
                        TextField("Number of subjects", text: $numberOfSubjects)
                    }
                    
                    let count = Int(numberOfSubjects) ?? 0
                    Text("Count: \(count)")
                    Section(header: Text("Subject grades")) {
                        if count>0 && count<10 {
                            ForEach(0 ..< count) { number in
                                TextField("Subject", text: $subject[number])
                                TextField("Grade", text: $grade[number])
                            }
                        }
                    }
                }
                VStack {
                    ForEach(students.details) { student in
                        Text(student.name)
                        ForEach(student.subjects) { subject in
                            HStack {
                                Text("Subject: \(subject.name)")
                                Text("Grade: \(subject.grade)")
                            }
                        }
                    }
                }
            }
            .navigationTitle("Student grades")
            .navigationBarItems(trailing:
                    Button(action: {
                        //let details = Details(name: name, subjects: [Details.Subjects(name: "Physics", grade: "A"), Details.Subjects(name: "Computer Science", grade: "A*")])
                        //students.details.append(details)
                        //^Above to append
                    }, label: {
                    Text("Save")
                })
            )
        }
    }
}

我尝试创建一个 [Subjects] 类型的变量,但在输入文本字段值后不允许我附加到它,它给了我错误:“类型 '()' 不能符合 'View';只有结构/枚举/类类型可以符合协议”(这是有道理的,因为它需要一个按钮)。一旦使用 ForEach 按下保存按钮,我也尝试过附加它,但这也会给我同样的错误。

【问题讨论】:

    标签: arrays class struct swiftui


    【解决方案1】:

    我认为您希望模型更改由您的 Students 班级负责。尝试向Students 添加一个公共方法并从您的视图中调用它,如下所示:

    class Students: ObservableObject {
        @Published var details = [Details]()
      
      public func addDetails(_ details : Details) {
        details.append(details)
      }
    }
    

    然后在视图中的按钮操作中,将students.details.append(details) 替换为对此方法的调用:

    let details = Details(name: name, subjects: [Details.Subjects(name: "Physics", grade: "A"), Details.Subjects(name: "Computer Science", grade: "A*")])
    students.details.append(details)
    

    这就是你想要做的吗?

    【讨论】:

      【解决方案2】:

      您的视图试图为单个视图做太多事情。您尝试在单个视图中添加学生和成绩。 Asperi 的答案是正确的。但是,您的错误表明您的代码有其他问题。尝试在隔离环境中运行下面的代码,它应该可以正常工作。 现在我只是为每个成绩添加了一个保存按钮,它将始终将成绩添加到第一个学生。

      import SwiftUI
      
      class Students: ObservableObject {
          @Published var details = [Details]()
      }
      
      struct Details: Identifiable {
          let id = UUID()
          let name: String
          
          struct Subjects: Identifiable {
              let id = UUID()
              let name: String
              let grade: String
          }
          
          var subjects: [Subjects]
      }
      
      struct TestStudentView: View {
          @StateObject var students = Students()
          @State private var name = ""
          @State private var numberOfSubjects = ""
          @State private var subject = [String](repeating: "", count: 10)
          @State private var grade = [String](repeating: "", count: 10)
          @State private var details = [Details.Subjects]()
          var body: some View {
              NavigationView {
                  Group {
                      Form {
                          Section(header: Text("Student details")) {
                              TextField("Name", text: $name)
                              TextField("Number of subjects", text: $numberOfSubjects)
                          }
                          
                          let count = Int(numberOfSubjects) ?? 0
                          Text("Count: \(count)")
                          Section(header: Text("Subject grades")) {
                              if count>0 && count<10 {
                                  ForEach(0 ..< count) { number in
                                      TextField("Subject", text: $subject[number])
                                      TextField("Grade", text: $grade[number])
                                      Button(action: {
                                          if students.details.count > 0 {
                                              var test = students.details[0]
                                              students.details[0].subjects.append(Details.Subjects(name: subject[number], grade: grade[number]))
                                          }
                                      }) {
                                          Text("Save")
                                      }
                                  }
                              }
                          }
                      }
                      VStack {
                          ForEach(students.details) { student in
                              Text(student.name)
                              ForEach(student.subjects) { subject in
                                  HStack {
                                      Text("Subject: \(subject.name)")
                                      Text("Grade: \(subject.grade)")
                                  }
                              }
                          }
                      }
                  }
                  .navigationTitle("Student grades")
                  .navigationBarItems(trailing:
                          Button(action: {
                              let details = Details(name: name, subjects: [Details.Subjects(name: "Physics", grade: "A"), Details.Subjects(name: "Computer Science", grade: "A*")])
                              students.details.append(details)
                              //^Above to append
                          }, label: {
                          Text("Save")
                      })
                  )
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-03-06
        • 2020-07-26
        • 2020-05-07
        • 1970-01-01
        • 2018-07-24
        • 2021-10-06
        • 1970-01-01
        • 1970-01-01
        • 2015-11-28
        相关资源
        最近更新 更多