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

SwiftUI替换单例为@Environment后崩溃:ExperimentManager未在环境中设置的问题求助

SwiftUI替换单例为@Environment后崩溃:ExperimentManager未在环境中设置的问题求助

我最近在把App里的单例实现替换成SwiftUI的@Environment来管理各类Manager依赖,结果一运行就崩溃了,抛出的致命错误是:

Thread 1: Fatal error: ExperimentManager not set in environment.

我已经做了一些排查:在App结构体的init里初始化experimentManager的位置加了断点,断点确实在崩溃前被命中了,说明这个实例是成功创建出来的,但就是没正确注入到环境中?

下面是我的相关代码,麻烦大家帮忙看看问题出在哪,或者给点调试的方向,非常感谢!

环境键定义代码

import SwiftUI

// MARK: - TaskManager
private struct TaskManagerKey: EnvironmentKey {
    static let defaultValue: TaskManager = {
        fatalError("TaskManager not set in environment.")
    }()
}

extension EnvironmentValues {
    var taskManager: TaskManager {
        get { self[TaskManagerKey.self] }
        set { self[TaskManagerKey.self] = newValue }
    }
}

// MARK: - AssessmentManager
private struct AssessmentManagerKey: EnvironmentKey {
    static let defaultValue: AssessmentManager = {
        fatalError("AssessmentManager not set in environment.")
    }()
}

extension EnvironmentValues {
    var assessmentManager: AssessmentManager {
        get { self[AssessmentManagerKey.self] }
        set { self[AssessmentManagerKey.self] = newValue }
    }
}

// MARK: - WorkoutManager
private struct WorkoutManagerKey: EnvironmentKey {
    static let defaultValue: WorkoutManager = {
        fatalError("WorkoutManager not set in environment.")
    }()
}

extension EnvironmentValues {
    var workoutManager: WorkoutManager {
        get { self[WorkoutManagerKey.self] }
        set { self[WorkoutManagerKey.self] = newValue }
    }
}

// MARK: - BlueprintManager
private struct BlueprintManagerKey: EnvironmentKey {
    static let defaultValue: BlueprintManager = {
        fatalError("BlueprintManager not set in environment.")
    }()
}

extension EnvironmentValues {
    var blueprintManager: BlueprintManager {
        get { self[BlueprintManagerKey.self] }
        set { self[BlueprintManagerKey.self] = newValue }
    }
}

// MARK: - GoalManager
private struct GoalManagerKey: EnvironmentKey {
    static let defaultValue: GoalManager = {
        fatalError("GoalManager not set in environment.")
    }()
}

extension EnvironmentValues {
    var goalManager: GoalManager {
        get { self[GoalManagerKey.self] }
        set { self[GoalManagerKey.self] = newValue }
    }
}

// MARK: - ImageManager
private struct ImageManagerKey: EnvironmentKey {
    static let defaultValue: ImageManager = {
        fatalError("ImageManager not set in environment.")
    }()
}

extension EnvironmentValues {
    var imageManager: ImageManager {
        get { self[ImageManagerKey.self] }
        set { self[ImageManagerKey.self] = newValue }
    }
}

// MARK: - ServiceManager
private struct ServiceManagerKey: EnvironmentKey {
    static let defaultValue: ServiceManager = {
        fatalError("ServiceManager not set in environment.")
    }()
}

extension EnvironmentValues {
    var serviceManager: ServiceManager {
        get { self[ServiceManagerKey.self] }
        set { self[ServiceManagerKey.self] = newValue }
    }
}

// MARK: - SuggestedGoalsDataSource
private struct SuggestedGoalsDataSourceKey: EnvironmentKey {
    static let defaultValue: SuggestedGoalsDataSource = {
        fatalError("SuggestedGoalsDataSource not set in environment.")
    }()
}

extension EnvironmentValues {
    var suggestedGoalsDataSource: SuggestedGoalsDataSource {
        get { self[SuggestedGoalsDataSourceKey.self] }
        set { self[SuggestedGoalsDataSourceKey.self] = newValue }
    }
}

// MARK: - ExperimentManager
private struct ExperimentManagerKey: EnvironmentKey {
    static let defaultValue: ExperimentManager = {
        fatalError("ExperimentManager not set in environment.")
    }()
}

extension EnvironmentValues {
    var experimentManager: ExperimentManager {
        get { self[ExperimentManagerKey.self] }
        set { self[ExperimentManagerKey.self] = newValue }
    }
}

App结构体代码

import PhotosUI
import Supabase
import SwiftData
import SwiftUI

@main
struct ImproveMyselfApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
    @StateObject private var accountManager: AccountManager
    @StateObject private var blueprintManager: BlueprintManager
    
    private var taskManager: TaskManager
    private var workoutManager: WorkoutManager
    private var assessmentManager: AssessmentManager
    private var goalManager: GoalManager
    private var imageManager: ImageManager
    private var serviceManager: ServiceManager
    private var suggestedGoalsDataSource: SuggestedGoalsDataSource
    private var experimentManager: ExperimentManager
    
    @State private var hasCompletedOnboarding = UserDefaults.standard.bool(
        forKey: "HasCompletedOnboarding"
    )
    @State private var isInitialized = false
    @State private var errorMessage: String?
    
    let userDataContainer: ModelContainer
    
    init() {
        do {
            userDataContainer = try ModelContainer(
                for: UserData.self, BeforePhoto.self, Blueprint.self, InspirationImage.self,
                QuoteFileUsage1.self, LifeAreaRating1.self, MentalState.self, SuggestedGoalChoices.self,
                SuggestedGoalPairEntity.self, TaskItem.self, TaskCompletion.self, ShareItem.self,
                Suggestion.self, Comment.self, Vote.self, Tag.self, WorkoutPlan.self, WorkoutExercise.self, Subtask.self
            )
            // 这里初始化了各类Manager,包括experimentManager,断点命中此处
            accountManager = AccountManager()
            blueprintManager = BlueprintManager(container: userDataContainer)
            taskManager = TaskManager(container: userDataContainer)
            workoutManager = WorkoutManager(container: userDataContainer)
            assessmentManager = AssessmentManager(container: userDataContainer)
            goalManager = GoalManager(container: userDataContainer)
            imageManager = ImageManager()
            serviceManager = ServiceManager()
            suggestedGoalsDataSource = SuggestedGoalsDataSource()
            experimentManager = ExperimentManager()
        } catch {
            fatalError("Failed to initialize ModelContainer: \(error)")
        }
    }
    
    var body: some Scene {
        WindowGroup {
            if hasCompletedOnboarding {
                MainTabView()
            } else {
                OnboardingView()
            }
            .environment(\.modelContext, userDataContainer.mainContext)
            .environmentObject(accountManager)
            .environmentObject(blueprintManager)
            // 怀疑这里漏了注入其他Manager到环境中
        }
    }
}

我现在最怀疑的点是:在App的body里,我只给accountManager和blueprintManager加了.environmentObject,但其他Manager(包括experimentManager)根本没通过.environment(\.experimentManager, experimentManager)这种方式注入到环境中?或者是不是某个子View在App还没完成环境注入的时候就提前读取了experimentManager?

麻烦大家帮忙分析下,谢谢啦!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:14:33