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:

  1. How can I ensure the ChildView has 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.

  2. I know @Query automatically 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 a FetchDescriptor in the view’s constructor, does the same hold true? As in will the view — depending on a FetchDescriptor inside 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.

0

There are 0 best solutions below