When I select a row in my NavigationView from TeamsView I get this error:
Fatal error: No ObservableObject of type UserManager found. A View.environmentObject(_:) for UserManager may be missing as an ancestor of this view.
UserManager is where I set up my Object
UserManager:
import Foundation
import FirebaseFirestore
import FirebaseFirestoreSwift
struct DBUser {
let userId: String
let email : String?
let photoUrl : String?
let dateCreated : Date?
}
final class UserManager: ObservableObject {
@Published var currentUser: DBUser?
static let shared = UserManager()
private init() {}
func createNewUser(auth: AuthDataResultModel) async throws {
var userData: [String: Any] = [
"user_id": auth.uid,
"date_created": Timestamp(),
]
if let email = auth.email {
userData["email"] = email
}
if let photoURL = auth.photoUrl {
userData["photo_url"] = photoURL
}
try await Firestore.firestore().collection("Users").document(auth.uid).setData(userData, merge: false)
}
func getUser(userId: String) async throws -> DBUser {
let snapshot = try await Firestore.firestore().collection("Users").document(userId).getDocument()
guard let data = snapshot.data(), let userId = data["user_id"] as? String else {
throw URLError(.badServerResponse)
}
let email = data["email"] as? String
let photoUrl = data["photo_url"] as? String
let dateCreated = data["date_created"] as? Date
return DBUser(userId: userId, email: email, photoUrl: photoUrl, dateCreated: dateCreated)
}
func addFavouriteTeamToUser(_ teamName: String, userId: String) {
Firestore.firestore().collection("Users").document(userId).setData(["favourite_team_name": teamName], merge: true)
}
}
TeamsView is the View that shows a list of teams in a NavigationView and when I press one the error occurs
TeamsView:
import SwiftUI
struct TeamsView: View {
@State private var showSignInView: Bool = false
@StateObject var vm = TeamsViewModel()
@State private var query = ""
@EnvironmentObject var userManager: UserManager
var body: some View {
NavigationView {
List {
ForEach(vm.filteredData) { team in
NavigationLink(destination: ProfileView(showSignInView: $showSignInView)) {
HStack {
TeamView(team: team)
}
.onTapGesture {
addUserFavouriteTeam(team)
}
}
}
}
.navigationTitle("Teams")
.searchable(text: $query, prompt: "Select your Favourite Team")
.onChange(of: query) { newQuery in vm.search(with: newQuery)
}
.onAppear() {
vm.search()
}
.overlay {
if vm.filteredData.isEmpty {
EmptyView()
}
}
}
}
private func addUserFavouriteTeam(_ team: Team) {
if let userId = userManager.currentUser?.userId {
userManager.addFavouriteTeamToUser(team.name, userId: userId)
}
}
}
struct TeamsView_Previews: PreviewProvider {
static var previews: some View {
TeamsView()
}
}
TeamView is the View I'm showing within the NavigationView in TeamsView
TeamView:
struct TeamView: View {
let team: Team
@EnvironmentObject var userManager: UserManager
var body: some View {
HStack{
Image(team.name)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
Text(team.name)
}
}
}
Finally, here's my RootView
RootView:
struct RootView: View {
@State private var showSignInView: Bool = false
@EnvironmentObject var userManager: UserManager
var body: some View {
ZStack {
if !showSignInView {
NavigationStack {
ProfileView(showSignInView: $showSignInView)
}
}
}
.onAppear() {
let authUser = try? AuthenticationManager.shared.getAuthenticatedUser()
self.showSignInView = authUser == nil
}
.fullScreenCover(isPresented: $showSignInView) {
NavigationStack {
AuthenticationView(showSignInView: $showSignInView).environmentObject(userManager)
}
.environmentObject(userManager)
}
}
}
struct RootView_Previews: PreviewProvider {
static var previews: some View {
let userManager = UserManager.shared
return RootView().environmentObject(userManager)
}
}
Update: I've tried reading other people with similar issues and they added .environmentObject(userManager) in their other views but I'm still having the issue. e.g. SwiftUI -> Thread 1: Fatal error: No observable object of type MyObject.Type found (EnvironmentObject in sheet)