2

Here I am having some trouble with Core Data and SwiftUI.

My main view has access to some information from an entity in Core Data.

And I want to pass this to a subview, using some kind of binding so that it can also access this data and possibly update it.

Here is one version of the code I tried.

On the main view side:

@Environment(\.managedObjectContext) var managedObjectContext
......
@FetchRequest(
    entity: MyEntity.entity(),
    sortDescriptors: [NSSortDescriptor(keyPath: \MyEntity.name, 
                                       ascending: true)]
) var myList: FetchedResults<MyEntity>

......

var body: some View {
    VStack {
      Button(action: {
      ..........
      }).sheet(isPresented: $showingList) {
        MyListView(localList: self.$myList,
                   moc:self.managedObjectContext,
                   ......)
    }
    .....
}

On the subview side:

struct MyListView: View {
    @Binding var localList: FetchedResults<MyEntity>
    .....
}

In the code above, the @FetchRequest is working, getting the information I expect. But after that, I am trying to do as if @FetchRequest was behaving like a @State. And it does not work. What is the proper way to give to my subview (i.e. MyListView) access to the data provided by the @FetchRequest?

I have obviously tried a few other variations of this code before writing this post, while reading some tutorials; but it still doesn't work.

Michel
  • 10,303
  • 17
  • 82
  • 179
  • I think you might need to re-think about the view hierarchy, ideally you could move the fetch list to the `MyListView` – Sudara Jul 22 '20 at 07:10
  • Yes, I could indeed, in theory. But I also tried this approach with no success. Ideally I'd be happy if I knew how to do both. – Michel Jul 22 '20 at 07:22

1 Answers1

2

You can't modify FetchedResults, because it is read-only, so just pass it as-is

MyListView(localList: self.myList,
           moc:self.managedObjectContext,
           ......)

and

struct MyListView: View {
    var localList: FetchedResults<MyEntity>
    .....
}

If you want MyListView behaves based on FetchRequest then inject it in there explicitly similar as you do for main view, CoreData caches fetched entities, so no drawback.

.... you have to pass context environment in sheet view explicitly for that, like MyListView().environment(.managedObjectContext, self.managedObjectContext)

Michel
  • 10,303
  • 17
  • 82
  • 179
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • yes if I use the code you suggest, indeed I can have access to the data. But for the second part of you proposal (which is what I want), for some reason that I don't understand the (at)FetchRequest is not working when placed in the subview. – Michel Jul 22 '20 at 07:36
  • 1
    @Michel, you have to pass context environment in sheet view explicitly for that, like `MyListView().environment(\.managedObjectContext, self.managedObjectContext)` – Asperi Jul 22 '20 at 07:39
  • Yes you are right, I just happened to find this same answer less than a minute ago here: https://stackoverflow.com/questions/59166513/coredata-and-swiftui-context-in-environment-is-not-connected-to-a-persistent-st – Michel Jul 22 '20 at 07:52