我有这个模型:
struct Training: Identifiable {
let id = UUID()
let name: String
let workout: [Workout]?
}
和:
struct Workout: Identifiable {
let id = UUID()
let name: String
let exercices: [Exercice]?
}
和:
struct Exercice: Identifiable {
let id = UUID()
let name: String
}
模型的数据来自环境对象。
该应用程序将启动,并显示一个空的培训列表,您可以在UI中添加培训。每个训练都有一个指向视图的导航链接,以将锻炼添加到每个训练中,并且在下一步中,您可以将锻炼添加到每个锻炼中。
按照我的逻辑,我使用上面显示的结构创建多维数组。
培训视图很简单:
struct TrainingsView: View {
@EnvironmentObject var appState: AppState
@State var showingDetail = false
var body: some View {
NavigationView {
VStack {
List {
ForEach (appState.trainings) { training in
NavigationLink(destination: WorkoutsView(training: training).environmentObject(self.appState)) {
Text(training.name)
}
}
.onDelete(perform: appState.removeTraining)
}
// Button to add trainings....
.navigationBarTitle(Text("Trainings").foregroundColor(Color.white))
}
}
}
}
WorkoutsView
看起来一样,但是我在列出家长培训的项目时遇到了问题:
struct WorkoutsView: View {
// ...
var training: Training
var body: some View {
VStack {
List {
ForEach (appState.trainings(training).workouts) { workout in // I know the appState call is incorrect, but I don't know how to access is correctly.
NavigationLink(destination: ExercicesView(workout)) {
Text(workout.name)
}
}
}
// ...
}
}
}
我已经尝试过:
List {
ForEach (0 ..< appState.trainings.count) {
NavigationLink(destination: WorkoutsView(training: $0).environmentObject(self.appState)) {
Text(appState.trainings[$0].name)
}
}
}
我可以在appState.trainings[training].workouts
中使用WorkoutsView
,但是我在NavigationLink行上收到错误Contextual closure type '() -> Text' expects 0 arguments, but 1 was used in closure body
,并且不知道该怎么办。
其他问题:如果这接近解决方案,我不需要该结构符合Identifiable吗?
答案 0 :(得分:0)
根据您要设计系统的方式,这里有2种广泛的方法。
1。。您的子视图了解应用程序状态,并可以直接对其进行修改。因此,父级需要传递索引/关键字,以便孩子找到要修改的数据:
struct TrainingsView: View {
@EnvironmentObject var appState: AppState
var body: some View {
NavigationView {
List(0..<appState.trainings.count) { i in
NavigationLink(destination: WorkoutsView(trainingIndex: i)) {
Text(self.appState.trainings[i].name)
}
}
}
}
}
struct WorkoutsView: View {
var trainingIdx: Int
@EnvironmentObject var appState: AppState
var body: some View {
VStack() {
TextField("training name: ", text: $appState.trainings[trainingIdx].name)
Button(action: {self.appState.trainings[trainingIdx].workouts.append(Workout(...))}) {
Text("Add workout")
}
}
}
}
2。。或者,您可能会说您不希望子视图了解应用程序的状态-您只希望他们修改一些静态struct
,自己拥有(而是由其父母拥有),则应使用@Binding
。
下面的示例在概念上说明了这一点:
struct TrainingsView: View {
@State var trainingA = Training(...)
@State var trainingB = Training(...)
var body: some Body {
NavigationView {
List {
WorkoutsView(training: $trainingA)
WorkoutsView(training: $trainingB)
}
}
}
}
struct WorkoutsView: View {
@Binding var training: Training
var body: some View {
VStack() {
TextField("training name: ", text: $training.name)
Button(action: { self.training.workouts.append(Workout(...)) }) {
Text("Add workout")
}
}
}
}