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

SwiftUI报错:已添加EnvironmentObject仍找不到AppViewModel

SwiftUI中EnvironmentObject找不到AppViewModel的问题

错误提示:
SwiftUI/EnvironmentObject.swift:70: Fatal error: No ObservableObject of type AppViewModel found. A View.environmentObject(_:) for AppViewModel may be missing as an ancestor of this view.

已在SignUpView的预览代码中添加了.environmentObject(AppViewModel()),但运行时仍触发上述错误,不清楚问题所在。

相关代码

SignUpView代码

import SwiftUI

struct SignUpView: View {
    
    @State var email = ""
    @State var password = ""
    @EnvironmentObject var model:AppViewModel
    
    var body: some View {
        ZStack {
            Color.theme.blue
            
            RoundedRectangle(cornerRadius: 30, style: .continuous)
                .foregroundStyle(LinearGradient(colors: [.orange, .red], startPoint: .topLeading, endPoint: .bottomTrailing))
                .frame(width: 1000, height: 475)
                .rotationEffect(.degrees(15))
                .offset(x: 20)
            
            VStack(spacing: 20) {
                
                Image("logo")
                    .resizable()
                    .scaledToFill()
                    .frame(width: 100)
                    .offset(y: 10)
                
                Text("Welcome")
                    .foregroundColor(.white)
                    .font(Font.custom("Poppins-Bold", size: 44))
                
                Text("Please Sign Up")
                    .foregroundColor(Color.theme.blue)
                    .font(Font.custom("Poppins-Regular", size: 22))
                    .offset(y:-20)
                
                // Email TextField
                TextField("", text: $email)
                    .disableAutocorrection(true)
                    .autocapitalization(.none)
                    .foregroundColor(.white)
                    .textFieldStyle(.plain)
                    .placeholder(when: email.isEmpty) {
                        Text("Email Address")
                            .foregroundColor(.white)
                            .font(Font.custom("Poppins-Light", size: 20))
                    }
                
                // Email TextBox
                Rectangle()
                    .frame(width:350, height: 1)
                    .foregroundColor(.white)
                    .padding(.top, -5)
                
                // Password TextField
                SecureField("", text: $password)
                    .disableAutocorrection(true)
                    .autocapitalization(.none)
                    .foregroundColor(.white)
                    .textFieldStyle(.plain)
                    .placeholder(when: password.isEmpty) {
                        Text("Password")
                            .foregroundColor(.white)
                            .font(Font.custom("Poppins-Light", size: 20))
                    }
                
                // Password TextBox
                Rectangle()
                    .frame(width:350, height: 1)
                    .foregroundColor(.white)
                    .padding(.top, -5)
                
                Button {
                    guard !email.isEmpty, !password.isEmpty else {
                        return
                    }
                    
                    model.signUp(email: email, password: password)
                } label: {
                    Text("Sign Up")
                        .frame(width: 200, height: 40)
                        .background(
                            Color.theme.blue
//                            RoundedRectangle(cornerRadius: 10, style: .continuous)
//                                .fill(.linearGradient(colors: [.red, .orange], startPoint: .topTrailing, endPoint: .bottomTrailing))
                            )
                        .cornerRadius(10)
                        .foregroundColor(.white)
                        .font(Font.custom("Poppins-Medium", size: 18))
                }
                
                Spacer()
                // Login Link
                HStack {
                    Text("Already Have An Account?")
                        .foregroundColor(.white)
                        .font(Font.custom("Poppins-Medium", size: 18))
                    NavigationLink("Login", destination: SignInView())
                        .foregroundColor(.orange)
                        .font(Font.custom("Poppins-Medium", size: 18))
                }.offset(y: 100)
            }
            .frame(width: 350, height: 60)
        }.ignoresSafeArea()
    }
}

struct SignUpView_Previews: PreviewProvider {
    static var previews: some View {
        SignUpView().environmentObject(AppViewModel())
    }
}

AppViewModel代码

import Foundation
import Firebase


class AppViewModel: ObservableObject {
    
    let auth = Auth.auth()
    @Published var signedIn = false
    
    var isSignedIn: Bool {
        // If it does NOT equal nil, then this means it is TRUE that, YES, we are indeed signed in. Yay!
        return auth.currentUser != nil
    }
    
    
    // If you want to pass information, you have to make placeholders for the variables to be passed in.
    func signUp(email: String, password: String) {
        auth.createUser(withEmail: email, password: password) { [weak self] result, error in
            guard result != nil, error == nil else {
                return
            }
            DispatchQueue.main.async {
                // Successfully signed up
                self?.signedIn = true
            }
        }
    }
    
    func login(email: String, password: String) {
        auth.signIn(withEmail: email, password: password) { [weak self] result, error in
            guard result != nil, error == nil else {
                return
            }
            
            DispatchQueue.main.async {
                // Successfully signed in
                self?.signedIn = true
            }
//            if error != nil {
//                print(error!.localizedDescription)
//            }
        }
    }
    
    func signOut() {
        try? auth.signOut()
        self.signedIn = false
        
    }
    
}

解决方案

预览中添加.environmentObject仅能解决预览界面的依赖问题,实际运行时必须在App的根视图层级注入共享的AppViewModel实例,步骤如下:

  1. 找到你的App入口文件(通常带有@main标记)
  2. 在根视图上添加.environmentObject,确保整个视图树都能访问到同一个AppViewModel实例:
@main
struct YourAppName: App {
    // 创建共享的视图模型实例
    private let appViewModel = AppViewModel()
    
    var body: some Scene {
        WindowGroup {
            NavigationStack { // SwiftUI 3及以下版本替换为NavigationView
                SignUpView()
            }
            // 注入环境对象
            .environmentObject(appViewModel)
        }
    }
}
  1. 额外注意:
    • 不要在每个视图中单独创建AppViewModel()实例,必须共享同一个实例,否则状态无法同步
    • 如果SignInView也使用了@EnvironmentObject var model:AppViewModel,无需单独为其添加.environmentObject,只要它是已注入环境对象的视图的子视图,就能自动获取到实例

内容的提问来源于stack exchange,提问作者Kiarra J.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 17:15:46