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

