You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:40:19