I’m new to SwiftUI so please do judge me, I would love to learn more.my program is producing error “Thread 1: Fatal error: No ObservableObject of type StoryVM found. A View.environmentObject(_:) for StoryVM may be missing as an ancestor of this view.” the same code using dummy data runs fine, but I am trying to implement it using firebase
struct StoryCellView: View {
@Binding var story: Story
var isSeen: Bool = false
@Environment(.colorScheme) var scheme
@EnvironmentObject var viewModel: StoryVM
var body: some View {
Text(story.name ?? "")
.font(.system(size: 12))
.fontWeight(.heavy)
.frame(minWidth: 62, maxWidth: 62, minHeight: 62, maxHeight: 62)
.clipShape(Circle())
.padding(2)
.background(scheme == .dark ? .black: .gray, in: Circle())
.padding(3)
.background(
LinearGradient(gradient: Gradient(colors: [.red, .orange, .red, .orange]), startPoint: .top, endPoint: .bottom)
.clipShape(Circle())
.opacity(isSeen ? 0 : 1)
)
.onTapGesture {
withAnimation{
//story.isSeen = true
viewModel.markStoryAsSeen(story)
viewModel.currentStory = story.id ?? ""
viewModel.showStory = true
print("Story tapped: (story.id ?? "")")
}
}
}
}
struct StoryCircleView: View {
@EnvironmentObject var viewModel: StoryVM
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 12, content: {
ForEach($viewModel.stories) { $story in
StoryCellView(story: $story) //revert back to original when auth is implemented
.environmentObject(viewModel)
}
})
.padding()
.padding(.top, 10)
}
.onAppear{
//viewModel.getStoriesCount()
viewModel.getStories()
}
}
}
the view model
@MainActor
final class StoryVM: ObservableObject {
@Published var showStory: Bool = false
@Published var currentStory: String = ""
@Published var stories: [Story] = []
private var isSeenStatus: [String: Bool] = [:]
private var lastDocument: DocumentSnapshot? = nil
// func getAllProducts() async throws {
// self.products = try await ProductsManager.shared.getAllProducts()
//
// }
func getStories(){
Task{
do{
let (newStories, lastDocument) = try await StoriesManager.shared.getAllStories(count: 8, lastDocument: lastDocument)
self.stories.append(contentsOf: newStories)
if let lastDocument {
self.lastDocument = lastDocument
}
newStories.forEach { story in
if isSeenStatus[story.id ?? ""] == nil {
isSeenStatus[story.id ?? ""] = false
}
}
print("you ran me!!!")
}catch{
print(error)
}
}
}
//will manage seen status when authentication has been implemented
func markStoryAsSeen(_ story: Story) {
if let storyID = story.id {
isSeenStatus[storyID] = true
}
}
func isStorySeen(_ story: Story) -> Bool {
if let storyID = story.id {
return isSeenStatus[storyID] ?? false
}
return false
}
func getStoriesCount() {
Task {
let count = try await StoriesManager.shared.getAllStoriesCount()
print("all story count (count)")
}
}
}
struct ContentView: View {
@Environment(.colorScheme) var colorScheme
@StateObject private var viewModel = StoryVM()
var body: some View {
GeometryReader{
let size = $0.size
let safeArea = $0.safeAreaInsets
NavigationStack{
StoryCircleView()
.overlay(
StoryView(size: size, safeArea: safeArea)
.toolbar(.hidden, for: .tabBar)
)
}
.environmentObject(viewModel)
}
}
}
please what am I doing wrong. thanks in advance
3
have you tried changing the @EnvironmentObject var viewModel: StoryVM to @stateObject var viewModel = StoryVM()
1