SwiftUI如何向子视图传递可选Workout模型并判断是否传入?
问题
我有一个依赖Workout模型对象的子视图,既可以从已有训练列表传入Workout对象进入,也可以直接无对象进入。需求是:传入对象则直接使用,未传入则立即创建新Workout并插入modelContext,利用SwiftData关联关系。
尝试用初始化方法实现逻辑,但系统强制要求传入workout参数:
var workout : Workout var passedWorkout : Workout? //If a workout was passed we assign it and if it was not we create a new one init() { if let unwrappedWorkout = passedWorkout { workout = unwrappedWorkout } else { workout = Workout(id: UUID()) print("inserting \(workout.id)") modelContext.insert(workout) } }
试过将workout改为@State属性、把逻辑移到onAppear,均无效。按建议在跳转前创建Workout传入,却触发Xcode错误:buildExpression required that toolbar item button conform to view,代码如下:
ToolbarItem(placement: .topBarTrailing) { //Create a New Workout NavigationLink() { //Making a Temporary workout that EditWorkoutView is reponsible for adding to ModelContext let workout = Workout(id: UUID(), name: "", exercises: [], startTime: Date.now, endTime: Date.now) EditWorkoutView(workout: workout) .navigationBarBackButtonHidden(true) }
解决方案
1. 子视图的可选参数与自动创建逻辑
将workout设为可选初始化参数,结合@Environment注入的modelContext处理插入逻辑(注意初始化时无法直接访问环境变量,需移至onAppear):
import SwiftUI import SwiftData struct EditWorkoutView: View { let workout: Workout @Environment(\.modelContext) private var modelContext // 支持传入已有Workout,或无参自动创建 init(workout: Workout? = nil) { if let existing = workout { self.workout = existing } else { self.workout = Workout(id: UUID(), name: "", exercises: [], startTime: Date.now, endTime: Date.now) } } var body: some View { // 你的视图内容示例 Text("训练名称:\(workout.name)") .onAppear { // 仅当新创建的Workout未被插入时执行操作 if !modelContext.inserted.contains(workout) { modelContext.insert(workout) print("插入新训练ID:\(workout.id)") } } } }
调用方式:
- 从已有列表进入:
EditWorkoutView(workout: existingWorkout) - 直接进入:
EditWorkoutView()
2. 修复ToolbarItem的错误
错误原因是NavigationLink缺少显式的标签视图,补充标签即可解决:
ToolbarItem(placement: .topBarTrailing) { NavigationLink { EditWorkoutView() .navigationBarBackButtonHidden(true) } label: { Image(systemName: "plus") // 可替换为文字如"新建训练" } }
如果坚持在跳转前创建Workout,需确保在环境变量可用的上下文中插入:
ToolbarItem(placement: .topBarTrailing) { NavigationLink { @Environment(\.modelContext) var modelContext let newWorkout = Workout(id: UUID(), name: "", exercises: [], startTime: Date.now, endTime: Date.now) modelContext.insert(newWorkout) EditWorkoutView(workout: newWorkout) .navigationBarBackButtonHidden(true) } label: { Image(systemName: "plus") } }
内容的提问来源于stack exchange,提问作者Milan Labus
相关产品推荐
相关产品推荐

