SwiftUI 在视图层次结构中传递变量

SwiftUI Passing variables in view hierarchy

我对我的 Swift / SwiftUI 应用程序的架构有疑问,该应用程序由一个 ListView、详细视图和详细视图组成,其中包含 2 个输入视图。具体来说,我想知道这样做是否正确。

架构如下:

列表视图启动视图模型控制器的@StateObjct。

@StateObject var viewModel = ListViewModelController()

查看模型控制器:

class ListViewModelController: ObservableObject {
@Published var model: ListViewModel

init() {
    self.model = ListViewModel()
 }
}

列表视图模型如下所示:

struct Exercise: Hashable, Identifiable {
let id =  UUID()
var name: String
var weight: String
var repetitions: String
}

struct ListViewModel {
var exercises = [
    Exercise(name: "crunches", weight: "80 kg", repetitions: "100"),
    Exercise(name: "curls", weight: "10 kg", repetitions: "12"),
    Exercise(name: "dips", weight: "Bodyweight", repetitions: "10")
]
}

我通过以下方式将练习变量传递给详细信息视图:

List {
        ForEach($viewModel.model.exercises, id: \.self) {$exercise in
            ExerciseConfigutationView(exercise: $exercise)
        }
        .onDelete(perform: delete)
        .onMove(perform: move)
    }

详细视图接受练习变量作为绑定:

@Binding var exercise: Exercise

问题是,每次我尝试显示 ListView 时,程序都会在没有警告或错误的情况下冻结。我想我对绑定 / 属性 包装器有一些误解。

感谢您的帮助。

ForEachid: \.self 是错误的,但更严重的问题是在 SwiftUI 中我们不使用视图模型对象,只使用模型对象。 View 数据结构已经是 SwiftUI 用来在屏幕上创建和更新实际视图(如 UILabel 等)的视图模型。

这是您的固定代码:

@StateObject var model = ListModel()

//The List model:
class ListModel: ObservableObject {
    @Published var var exercises = [Exercise(name: "crunches", weight: "80 kg", repetitions: "100"),
                                    Exercise(name: "curls", weight: "10 kg", repetitions: "12"),
                                    Exercise(name: "dips", weight: "Bodyweight", repetitions: "10")]
}

struct Exercise: Hashable, Identifiable {
    let id =  UUID()
    var name: String
    var weight: String
    var repetitions: String
}

// Pass the exercise variable to the detail view in the following way:
List {
        ForEach($model.exercises) { $exercise in
            ExerciseConfigurationView(exercise: $exercise)
        }
        .onDelete(perform: delete)
        .onMove(perform: move)
    }


// pass the exercise variable to the detail view in the following way:
@Binding var exercise: Exercise