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

Swift Data操作模型数组时崩溃问题求助

Swift Data嵌套模型崩溃问题解决

问题根源分析

  1. 错误使用@Relationship:Set类中的reps是基本数据类型(Int),@Relationship仅用于关联其他@Model类对象,不能用于基本类型,这是核心错误之一。
  2. 未将模型纳入Swift Data上下文管理:直接通过Routine()实例化对象,没有将其添加到ModelContext中,嵌套的Exercise和Set也未被上下文追踪,导致访问关联数组时崩溃。

修正后的完整代码

1. 模型定义(修复@Relationship误用)

@Model
class Routine {
    @Relationship var exercises: [Exercise]
    
    init() {
        self.exercises = []
    }
    
    // 初始化时添加默认数据的方法,需在上下文环境中调用
    func addDefaultExercise(context: ModelContext) {
        let set = Set(reps: 0)
        let exercise = Exercise(sets: [set])
        context.insert(set)
        context.insert(exercise)
        self.exercises.append(exercise)
    }
    
    func getRep() -> Int {
        guard let firstExercise = exercises.first, let firstSet = firstExercise.sets.first else {
            return 0
        }
        return firstSet.reps
    }
    
    func increase() {
        guard let firstExercise = exercises.first, let firstSet = firstExercise.sets.first else {
            return
        }
        firstSet.reps += 1
    }
}

@Model
class Exercise {
    @Relationship var sets: [Set]
    
    init(sets: [Set]) {
        self.sets = sets
    }
}

@Model
class Set {
    // 移除@Relationship,直接用普通属性
    var reps: Int
    
    init(reps: Int) {
        self.reps = reps
    }
}

2. App入口(保持原有容器配置)

@main
struct SwiftDataDemoApp: App {
    let container: ModelContainer
    
    init() {
        do {
            container = try ModelContainer(for: Routine.self, Exercise.self, Set.self)
        } catch {
            fatalError("Failed to create model container")
        }
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(container)
    }
}

3. 视图部分(使用@Query或手动插入上下文管理模型)

struct ContentView: View {
    // 获取上下文
    @Environment(\.modelContext) private var context
    // 使用@Query获取已存在的Routine,或初始化新对象
    @Query private var routines: [Routine]
    
    var body: some View {
        VStack {
            Text("Reps: \(currentRoutine.getRep())")
            
            Button(action: {
                currentRoutine.increase()
                // 手动保存上下文(可选,Swift Data通常自动处理,但显式保存更稳妥)
                try? context.save()
            }) {
                Text("Increase!")
            }
        }
        .onAppear {
            // 如果没有现有Routine,创建并添加到上下文
            if routines.isEmpty {
                let newRoutine = Routine()
                context.insert(newRoutine)
                newRoutine.addDefaultExercise(context: context)
                try? context.save()
            }
        }
    }
    
    // 获取当前使用的Routine
    private var currentRoutine: Routine {
        routines.first ?? Routine()
    }
}

关键修正点说明

  • 移除Set类中reps的@Relationship标记,基本数据类型无需关联配置。
  • 所有@Model对象必须通过ModelContext.insert(_:)方法添加到上下文,确保Swift Data能够追踪和管理这些对象及其关联关系。
  • 在视图中通过@Environment(\.modelContext)获取上下文,使用@Query查询现有数据,避免直接实例化未被管理的模型对象。
  • 添加安全判断(guard let),防止数组为空时的越界访问,提升代码健壮性。

内容的提问来源于stack exchange,提问作者Tobilence

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 11:43:16