Taylor Hartman
Taylor Hartman

Reputation: 11

Fatal error in ModelContainer.swift line 144 - failed to find currently active container for class

This error only appears in Preview - I am able to run my app fine.

I have a modification sheet that I want to build out in SwiftUI but the preview will not work which is putting a damper on my productivity. I am getting this error when I try to build the preview:

"failed to find a currently active container for Habit"

Here are my Sample goals data I am using to populate the container I am using for previews:

struct SampleGoals {
    static var contents: [Goal] =
        [
            Goal(name: "Spanish B2", id: "dasfdsa", habits: [
                Habit(name: "Comprehensible input", id: "dsafda", frequency: .daily),
                Habit(name: "Study Grammar", id: "djsakfdhjska", frequency: .weekly)
             ]),
             Goal(name: "Goal 2", id: "ashdjskaf", habits: [
                Habit(name: "Habit name", id: "dsafe", frequency: .daily)
             ])
        ]
}

Here are my models:

@Model
class Habit: Identifiable {
    var frequency: Frequency
    var name: String
    var isDone: Bool
    @Attribute(.unique) let id: String

    init(
        name: String,
        id: String,
        frequency: Frequency = .daily,
        isDone: Bool = false
    ) {
        self.name = name
        self.frequency = frequency
        self.isDone = isDone
        self.id = id
    }
}

@Model
class Goal: Identifiable {
    var name: String
    @Attribute(.unique) let id: String
    let habits: [Habit] = [Habit]()

    init(name: String, id: String, habits: [Habit]) {
        self.name = name
        self.habits = habits
        self.id = id
    }
}

Frequency is an enum that conforms to codable.

Here is my model container:

@MainActor
let previewContainer: ModelContainer = {
    do {
        let config = ModelConfiguration(for: Goal.self, Habit.self, isStoredInMemoryOnly: true)
        let container = try ModelContainer(
            for: Goal.self, Habit.self, configurations: config
        )
        for goal in SampleGoals.contents {
            container.mainContext.insert(goal)
        }
        return container
    } catch {
        fatalError("Failed to create container")
    }
}()

And here is how i'm applying the container for the preview:

#Preview {
    ModifyGoalView(
        modifyType: .edit,
        modifyGoalPresented: .constant(true),
        goal: SampleGoals.contents[0])
    .modelContainer(previewContainer)
}

I'm using this project to learn SwiftData and i've no clue why this is occurring.

I have found a few answers around stack overflow and the internet which I have tried to apply with no avail. Originally I did not have the Habit model included in the model configurations' persistent models and one response I found on reddit said to include it - this did not help. I also added the models to the Model configuration explicitly which also did not help. I have cleaned the project, deleted it from the simulator, and deleted my derived data as well.

Upvotes: 0

Views: 1207

Answers (2)

onetwosamp
onetwosamp

Reputation: 11

I believe Paul Hudson provides the answer you are looking for here:

https://www.hackingwithswift.com/quick-start/swiftdata/how-to-use-swiftdata-in-swiftui-previews

You need to create a ModelContainer using a ModelConfiguration to store the data in memory only. Then finally create your sample data.

Paul's example below:

#Preview {
    let config = ModelConfiguration(isStoredInMemoryOnly: true)
    let container = try! ModelContainer(for: User.self, configurations: config)

    for i in 1..<10 {
        let user = User(name: "Example User \(i)")
        container.mainContext.insert(user)
    }

    return ContentView()
        .modelContainer(container)
}

Upvotes: 1

Florian
Florian

Reputation: 1

I keep encountering similar issues, and my best guess so far is that the container isn't ready by the time your preview needs it. It doesn't affect your app outside of the previews because you most likely create the container long before this view is called.

Could you try wrapping your view in some sort of container and applying the modelContainer modifier to this container instead?

#Preview {
    struct Container: View {
        var body: some View {
            ModifyGoalView(
                modifyType: .edit,
                modifyGoalPresented: .constant(true),
                goal: SampleGoals.contents[0])
        }
    }
    
    return Container().modelContainer(previewContainer)
}

Upvotes: 0

Related Questions