I have a ChildView that you can access via NavigationLink and that will display in a NavigationSplitView’s detail pane.
NavigationSplitView {
ListView()
} detail: {
}
And
.navigationDestination(for: ChildModel.self) { post in
ChildView()
}
ChildView declares an Environment property for the model context:
@Environment(\.modelContext) private var modelContext
It also has a SwiftData @Query property declared to retrieve all stored DbModel objects:
@Query private var dbModel: [DbModel]
However, it always returns empty (when it is not true) and I see this warning pop:
Set a .modelContext in view's environment to use Query
I have seen Query() in view with model container attached shows error saying it does not have a model container which is similar but I wanted to follow up for a better understanding.
If I follow the advice in the answer above, and drop the @Query to replace with a FetchDescription in the ChildView constructor:
init() {
let predicate = #Predicate<DbModel> {
$0.id == self.id
}
let descriptor = FetchDescriptor<DbModel>(predicate: predicate)
if let models = try? modelContext.fetch(descriptor) {
/// do something here
}
}
It crashes:
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: SwiftData.SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer)
And has an accompanying warning:
Accessing Environment's value outside of being installed on a View. This will always read the default value and will not update.
If I instead I refer to a reference of the context that I store after an app launch, it works fine:
if let models = try? AppController.shared.modelContextReference.fetch(descriptor) {
That’s progress, but I would appreciate clarification on two things:
How can I ensure the
ChildViewhas environment access to the model context from a SwiftUI perspective, and for it to return the correct results (with no warning)? As in without needing to refer to a stored reference inside a class object.I know
@Queryautomatically stays up to date every time my data changes, and will reinvoke my SwiftUI view so it stays in sync. However, given I’m being forced to use aFetchDescriptorin the view’s constructor, does the same hold true? As in will the view — depending on aFetchDescriptorinside the.init()and not a@Query— also update whenever there are changes detected to the DbModel set?
The wider context is I am only interested in DbModel results for ChildView that are relevant (i.e. share the same id). So I’m also curious whether — short of having ability to dynamically query — that this will perform similarly to a @Query that has a filter defined with no dynamic value check.