MatFetsch
MatFetsch

Reputation: 65

Preview canvas crashing because environmentObject not set properly

I have my preview canvas crashing because the environmentObject is not properly set. The app itself builds and run properly.

Error message.

app crashed due to missing environment of type: TaskModel. To resolve this add .environmentObject(TaskModel(...)) to the appropriate preview.

My View with the #Preview macro looks like this.

struct CopyTaskListScreen: View {
    @EnvironmentObject private var taskModel: TaskModel
    
    var body: some View {
        NavigationStack {
            List(taskModel.tasks.sorted(by: <), id: \.key) { task in
                Text(task.value.title)
            }
        }
    }
}
#Preview {
    CopyTaskListScreen()
        .environmentObject(TaskModel(//how to call TaskDataService here?))
}

My TaskModel looks the following. I inject the TaskDataService with the ITaskData protocol. The TaskDataService accepts all data adapters implementing the ITaskData protocol and hand it over to my TaskModel.

@MainActor
class TaskModel: ObservableObject {
    @Published var tasks: [UUID: Task] = [:]
    
    var data: TaskDataService
    
    init(data: ITaskData) {
        self.data = TaskDataService(data: data)
        readTasks()
    }

I tried to inject the environment in #Preview the same way I did it in @main. But with the same result. Preview canvas is crashing.

@main
struct mTaskApp: App {

    var body: some Scene {
        WindowGroup {
            MainScreen()
              .environmentObject(TaskModel(data: TaskDataService(data: RemindersDataAdapter())))

Upvotes: 1

Views: 43

Answers (1)

malhal
malhal

Reputation: 30746

Normally your service would be an EnvironmentKey, e.g.

@Environment(\.taskDataService) var taskDataService
@EnvironmentObject private var taskModel: TaskModel

And would use it like this

.task {
    await taskDataService.load(into: taskModel)
}

Or better (where results is State):

.task {
    results = await taskDataService.load()
}

Then in preview it would be:

#Preview {
    CopyTaskListScreen()
        .environment(\.taskDataService, MockTaskDataService())
        .environmentObject(TaskModel())
}
protocol TaskDataService{}
struct RealTaskDataService: TaskDataService{}
struct MockTaskDataService: TaskDataService{}

Upvotes: -1

Related Questions