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

SwiftUI调用结构体变量时出现No ObservableObject类型错误求助

问题分析与解决方案

错误核心原因

你遇到的No ObservableObject of type StatsNavigationManager found错误,本质是环境对象的注入逻辑完全搞反了:

  • @EnvironmentObject的作用是从父视图的环境中读取已注入的ObservableObject实例,而不是在当前视图内部声明后再自己注入。
  • 你在StatsView里用@EnvironmentObject声明statNavManager,又在自己的NavigationView上添加.environmentObject(self.statNavManager),此时self.statNavManager还未从环境中获取到实例,相当于注入了一个空对象,自然会触发错误。

正确解决方案步骤

1. 在父视图中创建并注入环境对象

必须在包含StatsView的上层父视图(比如App入口、TabView页面)中创建StatsNavigationManager实例,再通过.environmentObject()注入到环境中。

示例(App入口):

@main
struct CrimeTrackingApp: App {
    // 用@StateObject持有ObservableObject实例,确保生命周期与App一致
    @StateObject private var statNavManager = StatsNavigationManager()
    
    var body: some Scene {
        WindowGroup {
            TabView {
                StatsView()
                    .tabItem { Label("Stats", systemImage: "chart.bar") }
                    // 在这里注入环境对象
                    .environmentObject(statNavManager)
                // 其他标签页...
            }
        }
    }
}

2. 修改StatsView代码

移除StatsView内部的.environmentObject(self.statNavManager)代码,保留@EnvironmentObject声明即可:

final class StatsNavigationManager: ObservableObject {
    @Published var screen: Screens? {
        didSet {
            print("📱 \(String(describing: screen))")
        }
    }
    
    func push(to screen: Screens) {
        self.screen = screen
    }
    
    func popToRoot() {
        self.screen = nil
    }
}

struct StatsView: View {
    let test = cityClass()
    
    struct Input{
        var zip: String = ""
    }
    
    @State private var input: Input = .init()
    @FocusState private var inputFocused: Bool
    // 保留@EnvironmentObject声明,从父视图环境中获取实例
    @EnvironmentObject var statNavManager: StatsNavigationManager

    var body: some View {
        NavigationView {
            ZStack {
                Color.blue
                VStack {
                    inputTxtVw
                    submitBtn
                }
                .toolbar {
                    ToolbarItemGroup(placement: .keyboard) {
                        Spacer()
                        Text("Search")
                        Button("Retrieve Data") {
                            statNavManager.push(to: .statsPage)
                        }
                        .background(
                            NavigationLink(destination: CityView(),
                                           tag: .statsPage,
                                           selection: $statNavManager.screen) { EmptyView() }
                        )
                    }
                }
                .onSubmit(of: .text, submit)
            }
        }
        // 移除这里的.environmentObject(self.statNavManager)
    }
    
    // 补充你未贴出的视图组件实现
    private var inputTxtVw: some View {
        TextField("Enter ZIP", text: $input.zip)
            .focused($inputFocused)
            .padding()
            .background(Color.white)
            .cornerRadius(8)
    }
    
    private var submitBtn: some View {
        Button("Submit") {
            submit()
        }
        .padding()
        .background(Color.white)
        .cornerRadius(8)
    }
    
    private func submit() {
        // 这里添加你的提交逻辑
        statNavManager.push(to: .statsPage)
    }
}

关键注意点

  • @StateObject:用于在父视图中持有ObservableObject实例,确保其生命周期与父视图绑定,避免重复创建。
  • 环境对象的注入层级:必须在目标视图的上层祖先视图上注入,目标视图通过@EnvironmentObject读取,不能在视图内部自我注入。
  • 如果你用的是SwiftUI 3.0以下版本,父视图中改用@ObservedObject代替@StateObject即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 12:30:46