App crashing when using swiftdata

I’m a complete beginner to Swift, but I’m trying to make some random practice app that uses swiftData. I’m using swift playground on my iPad pro. Anytime I try to save a class model, the app crashes. But this only happens in the preview window. When I actually run the app, the app crashes when I enter a specific navigation link (Schedule, in the following code)

Here is the code from each file in my app.

MyApp:

import SwiftUI
import SwiftData

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }     
    }
}

ContentView:


import SwiftUI
import SwiftData

struct ContentView: View {
    
    
    
    @Environment(\.modelContext) var modelContext
    var body: some View {
        NavigationView{
            
            VStack(spacing:35){
                
                NavigationLink("Unit Converter"){
                    
                    
                    VStack(spacing: 50){
                        NavigationLink("Length"){
                            UnitConversions.init(unitConversions: ["mm" : 1000.0, "cm" : 100.0, "m": 1.0, 
                                                                   "km" :0.001, "in" : 39.37, "ft" : 3.281, "mi" : Double(1.0/1609.0)], units: ["m", "cm", "mm", "km", "in", "ft", "mi"])
                            
                        }
                        NavigationLink("Mass"){
                            UnitConversions.init(unitConversions: ["g": 1.0, "mg": 1000.0, "kg": 0.001, "ozs" : 0.0353, "lbs" : 0.0022, "tonne" : 0.000001], units: ["g", "mg", "kg", "ozs", "lbs", "tonne"])
                        }
                        NavigationLink("Volume"){
                            UnitConversions.init(unitConversions: ["l": 1.0, "ml" : 1000.0, "tsp" : 202.9, "tbsp" : 67.6, "cup" : 4.23, "quart" : 1.057, "gallon" : 0.2642, "pint" : 2.113], units: ["l", "ml", "tsp", "tbsp", "cup", "quart", "gallon", "pint"])
                        }
                        //NavigationLink("Temperature"){
                            //UnitConversions.init(unitConversions: ["ºC": 1.0, "ºF" : 0.0, "K": 0.0], units: ["ºC", "ºF", "K"])
                        //}
                        NavigationLink("Time"){
                            UnitConversions.init(unitConversions: ["ms" : 3600000.0, "s" : 3600.0, "min" : 60.0, "hrs" : 1.0, "day" : 0.0416666667, "month" : 0.00137, "year" : 0.000114154 ], units: ["hrs", "ms", "s", "min", "day", "month", "year"])
                        }
                        
                        .navigationTitle("Units")
                        
                        
                        
                    }
                    
                }
                
                //NavigationLink("Calculator"){
                    
                //}
                NavigationLink("Schedule"){
                    Schedule.init(selectedDate: Date.now)
                    
                }
                NavigationLink("Assignments"){
                    AssignmentView.init()
                }
            }
            .navigationTitle("Tools")
            
            .modelContainer(for: Assignment.self)

        }
    }

}


Schedule:

import SwiftUI
import SwiftData

struct Schedule: View {
   @State var selectedDate : Date
    var body: some View{
        VStack() {
            Text(selectedDate.formatted(date: .abbreviated, time: .omitted))
                .font(.system(size: 40))
                .bold()
                .foregroundColor(Color.accentColor)
                .padding()
                .animation(.snappy(), value: selectedDate)
                .frame(width: 600)
            Divider().frame(height: 1)
            DatePicker("Select Date", selection: $selectedDate, displayedComponents: [.date])
                .padding(.horizontal)
                .datePickerStyle(.graphical)
                
            Divider()
                NavigationLink("Add Assignments") {
                    AddAssignment.init()
                }
            
        }
        .padding(.vertical, 200)
    }
}

UnitConversions (not relevant to my error, but figured i’d throw it in)

import SwiftUI

struct UnitConversions: View {
    var unitConversions: [String: Double]
    var units: [String]
    
    @State private var unit1 = ""
    @State private var unit2 = ""
    @State private var unit1Amount = 0.0
    var body: some View{
        VStack{
            TextField("Enter your Number", value: $unit1Amount, format: .number)
                .textFieldStyle(.roundedBorder)
                .padding()
            
            Picker("Starting Unit", selection: $unit1) {
                ForEach(units, id: \.self) {
                    Text($0)
                }
            }
            .padding()
            
            Picker("Converting Unit", selection: $unit2) {
                ForEach(units, id: \.self) {
                    Text($0)
                }
                
            }
            .padding()
            Text("\((unit1Amount * unitConversions[unit2, default : 1.0] / unitConversions[unit1, default : 1.0]).formatted())")
                
        }
    }
}

Assignment:

import Foundation
import SwiftUI
import SwiftData

@Model
class Assignment {
    var dueDate: Date
    var assignmentName: String
    var classroomName: String
    init(dueDate: Date = .distantFuture, name: String = "", classroomName: String = ""){
        self.dueDate = dueDate
        self.assignmentName = name
        self.classroomName = classroomName
    }
}

AssignmentView:

import SwiftUI
import SwiftData


struct AssignmentView: View {
    @Query var assignments: [Assignment]
    var body: some View {
        VStack {
            ForEach(assignments) {assignment in 
                Text(assignment.classroomName)
                
            }
            
        
            
        }
    }
    
}

AddAssignment:

import SwiftUI
import SwiftData

struct AddAssignment: View {
    
     @State var newAssignment = Assignment.init(dueDate: .now, name: "", classroomName: "")
    @Environment(\.modelContext) var modelContext
    func saveInfo(){
        modelContext.insert(newAssignment)
    }
    
    var body: some View {
        VStack{
            TextField("Assignment Name", text: $newAssignment.assignmentName)
                .textFieldStyle(.roundedBorder)
                .padding()
            TextField("For Class", text: $newAssignment.classroomName)
                .textFieldStyle(.roundedBorder)
                .padding()
            Button(
                action: {saveInfo()},
                label: { Text("Add Assignment") }
            )            
            
        }
    }
}

Since I’m a beginner, I followed Hacking with Swift’s tutorial for swiftData. I’ve been trying to fix this for a long time, but I really don’t know what it is. Anyone with more knowledge, could you ELI5 what I’m doing wrong?

EDIT: The error I’m getting when it crashes is:

A fatal error was found in ModelContainer.swift at line 144, failed to find a currently active container for Assignment

I haven't tried SwiftData out further than messing with a tutorial, and am a bit short on time right now, but on first glance:
I think the problem might be that you have set the .modelContainer(for: Assignment.self) on the VStack which is inside the ContentView. However, you already specify @Environment(\.modelContext) var modelContext to be there for ContentView. I don't know how the property wrapper (the @Environment) works when the modelContainer state modifier that sets up the actual storage is only ever provided the first time inside the view it is defined in.

If I see this correctly you do not even use the modelContext anywhere inside the ContentView, so I think you can get rid of it. The various child views should be fine, I think.

In general, I wonder why you only define the it on ContentView, it seems there is only one model and storage your app will use, so why not simply define it on the WindowGroup (in your MyApp type) in the first place? I'd do it like that, that's the way the Xcode template does it and also how most simple apps work.

I did have that originally actually, but it would work with my app. I saw some forums say that moving it to ContentView could help. I just tried switching it back to the WindowGroup, but the same error occurs as in ContentView unfortunately. I also tried removing the modelContext variable and it also didn’t change anything.

Okay, that's surprising to me, but I have another hunch...
I quickly copy & pasted your code into a demo project in Xcode, but after adding the necessary previews and adding the container to the WindowGroup as explained above I was not able to recreate the error.

This makes me believe you set up the .modelContainer wrongly somehow, perhaps only briefly in a previous run. There's various ways in which that could have happened, but if any of those did not use an in memory container, the problems would be persisted. If that is the case you have to fix the code (see below) and chose "Delete All Preview Data" from the context menu that opens when you long-press on the "App Preview" tab on the upper right section of your app (right above the actual preview).

Code fixes:

  1. As said you should add .modelContainer(for: Assignment.self) further up your hierarchy, I'd say the WindowGroup. I don't know why someone would tell you otherwise, because while there are use cases where the modifier makes sense (also) somewhere else, your app so far does not look like that. And you probably want to have the same storage everywhere in the app (i.e. storing the assignments in a different container than the one that is used to show their list is kind of pointless :smile:).
  2. You should make sure that containers used in previews are in memory. That way you avoid storage issues (and also disk space). I am not sure if the Swift Playgrounds app specifically (especially on the iPad) does that somehow automatically, but you can be explicit: For all views that require a modelContext, make sure they have previews like this:
#Preview {
    ContentView()
        .modelContainer(for: Assignment.self, inMemory: true)
}

This last one would go into the ContentView.swift file, other views that have previews and use any modelContext should get the same modifier.

Please let me know if that helps (don't forget to "Delete All Preview Data" after changing your code). If not, I can also investigate it further on the iPad, which I haven't done yet. As a matter of fact, I am impressed how far that has come, I didn't check the app in quite a while (since I work in Xcode).