I'm refactoring some code, and happens that i had a bunch of unrelated viewModel instances, and now i'm trying to do this right. but, during the process i'm having the error "Thread 1: Fatal error: No ObservableObject of type ShortcutsViewModel found. A View.environmentObject(_:) for ShortcutsViewModel may be missing as an ancestor of this view." . I'm going to let some pieces of code that I think gonna be useful:
(a detail that i dont know if it's important, is that the contentView is part of a personal package, and I dont know if it has some influence in the error (i'm importing the package in my project))
principal view:
WidgetContentView(
widgetView: WidgetViewShowing(
maxOfItemsPerPage: 1,
numberOfWidgetRows: 1
),
viewModel: ShortcutsViewModel(
widgetNamePrefix: "smallWidget",
contract: ShortcutWidgetManager()
)
)
view that starts StateObject:
public struct WidgetContentView<WidgetViewShowing: View>: View {
private var widgetView: WidgetViewShowing
private var total: Int {
viewModel.shortcutsViewData?.count ?? 0
}
@StateObject public var viewModel: ShortcutsViewModel
public init(
viewModel: ShortcutsViewModel
) {
_viewModel = StateObject(wrappedValue: viewModel)
}
public var body: some View {
ZStack {
HStack(content: {
widgetView
.environmentObject(viewModel)
})
}
}
}
view EnvironmentObject that would be using instance from StateObject:
public struct WidgetViewShowing: View {
@EnvironmentObject var viewModel: ShortcutsViewModel
var shortcutsViewDataList: [ShortcutViewData]? {
viewModel.shortcutsViewData // THE ERROR IS HAPPENING HERE
}
}
@StateObject
is for loading or saving models and is used like this:
@StateObject prviate var modelStore = ModelStore()
The reason for this is to ensure it does not passed any dependencies because that would invalidate its use as a source of truth. I.e. it would not know that any values passed in have changed since the first time it was init. E.g. in your code, it would not detect any changes to the supplied widgetNamePrefix
.
Another issue in your code is this memory leak, both ShortcutsViewModel
and ShortcutWidgetManager
are leaked. You are not supposed to init objects in body
like this, only simple values or structs.
ShortcutsViewModel(
widgetNamePrefix: "smallWidget",
contract: ShortcutWidgetManager() // leaked object
) // leaked object
To resolve these issues, you'll need to learn @State
and @Binding
, computed vars, and how to group related dynamic vars in a custom @State
struct with mutating func for logic. This is just how SwiftUI works for view data I'm afraid, legacy view model objects just won't work right.