SwiftUI and CoreData

I am getting an error when trying to fetch objects in SwiftUi in a form sheet modal in iOS 13.


Here's the error:

[SwiftUI] Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x600003218620>


I am able to run a fetchRequest from a list view, but not in the modal.

Has anyone else seen this issue?


I set the Environment context in the SceneDelegate:


if let windowScene = scene as? UIWindowScene {
      let window = UIWindow(windowScene: windowScene)
      let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
      //managedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
      window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(sampleViewModel).environmenbject(customerViewModel).environment(\.managedObjectContext, managedObjectContext))
      self.window = window
      window.makeKeyAndVisible()


In the ContentView:

import SwiftUI

struct ContentView: View {
    @State var isPresented = false
    
    var body: some View {
        NavigationView {
            VStack {
                // Search bar, filter, and divider
                SampleListView()
            }
            .sheet(isPresented: $isPresented) {
                NewSampleView()
            }
            .navigationBarTitle("Samples")
            AddSampleButton(isNewSamplePresented: $isPresented)
        }
    }
}


Able to see items in the SampleListView:

struct SampleListView: View {
    @EnvironmentObject var viewModel: SampleListViewModel
    @FetchRequest(fetchRequest: Sample.allSamplesFetchRequest()) var samples: FetchedResults
    var body: some View {

        List(self.samples) { sample in
            VStack(alignment: HorizontalAlignment.leading) {
                NavigationLink(destination: SampleView(activeSampleModel: ActiveSampleViewModel(sample: sample))) {
                    Spacer()
                    Text(sample.trackingNumber ?? "")
                    Spacer()
                    Text(sample.sampleId ?? "")
                    Spacer()
                }
            }

        }
    }
}


But I get the error when presenting the NewSampleView (I've tried using a fetchRequest defined in the view as well as one defined in the NSManagedObject subclass but the fetch is always failing with the above error) :

import SwiftUI
import CoreData

struct NewSampleView : View {
    @State var customerId = ""
    @State var sampleDate = Date(timeIntervalSinceNow: 0)
    @State var receiptDate = Date(timeIntervalSinceNow: 0)
    @State var customerServiceSampleNumber = ""
    @State var notes = ""

    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(fetchRequest: fetchRequest(), animation: nil) var customers: FetchedResults
    
    var body: some View {
        
        List(self.customers) { customer in
            VStack(alignment: HorizontalAlignment.leading) {
                    Spacer()
                    Text(customer.customerId ?? "")
                    Spacer()
                }
            }
    }
    
    
    static func fetchRequest() -> NSFetchRequest {
        let request: NSFetchRequest = Customer.fetchRequest() as! NSFetchRequest
        request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
          
        return request
    }

Accepted Reply

Hi bryonCat

I found similiar issue. It seems to be general problem of beta 5. Just create Hello World project and pass any EnviromentalObject to modal view. You should get the same error message.

Replies

Hi bryonCat

I found similiar issue. It seems to be general problem of beta 5. Just create Hello World project and pass any EnviromentalObject to modal view. You should get the same error message.

Thanks, that's what I was thinking - everything works if I don't use a modal - hope it's all fixed up in beta 6. 🙂

Xcode 11 GM seed 1 and it seems this is still an issue unresolved.

I did create a simple project to show how to connect Core Data when presenting modally a view.

https://github.com/R4S3CDev/CoreData_Integration

I'm seeing this error in XCode 11 GM seed 1 also. If I access the @FetchRequest in my root View it returns data correctly. If I try to use the same fetch is a child view I get: [SwiftUI] Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x2827ac460>.


It is like the Environment losses the MOC relationship to the persistent store coordinator in the child views.


I think I found a solution for the above issue. I needed to pass the MOC to the child view by adding it to the environment of that view. This allows the FetchRequest in child View (ProspectSelection) to return and not give the above error.

ProspectSelection(userData: self.userData, onDismiss: {
                        self.showingSearchCriteria = false
                        self.setModelViewData()
                    }).environment(\.managedObjectContext, CoreDataStack.shared.persistentContainer.viewContext)


I thought the purpose the an EnvironmentObject is to safely allow every View to access an Object and not passed around. This does not seem to be working correctly. I may file a bug.


For now I'll have to put the MOC in the enviroment of every View that needs a @FetchRequest.

Thx , bcalkin2 you really made my day!!


(Xcode Version 11.1 (11A1027))


Here is how I did it (as a rookie I am, it took a while to decode what you really did 🙂) (see bold text)


Extra: - I´m also using .background(EmptyView().sheet(is...... to allow the HomeView to have more than one modal sheet to pop up...


import SwiftUI


struct HomeView: View {

@State private var showUserListView = true

@State private var showRegisterNewUserView = false


@ObservedObject var userValidation = UserValidationModel()


var body: some View {

ZStack {

Color(.darkGray).edgesIgnoringSafeArea(.all)

VStack {

Spacer()

Text("Main Screen").font(.largeTitle)


Button(action: {self.showRegisterNewUserView = true}) { Text("RegisterNewUser")}

Button(action: {self.showUserListView = true}) { Text("showUserListView")}


Spacer()

}

}

.background(EmptyView().sheet(isPresented: $showUserListView) {

UserListView ()

.environment(\.managedObjectContext, (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext)

})

.background(EmptyView().sheet(isPresented: $showRegisterNewUserView)

RegisterNewUserView()

.environment(\.managedObjectContext, (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext)

})


}

}


struct ContentView_Previews: PreviewProvider {

static var previews: some View {

HomeView()

}

}

The workaround fails in Xcode 11.2 beta 2 (11B44) with FetchRequest instead of wrapper @FetchRequest.

Is there now a solution known? I have still this problem.

@RΔSΞC

Thank's a lot for your sample project! It saved my day!
Your solution resolves the problem with ease.
If everyone comes by with the same problem, just check out the sample project on GitHub.

One just has to pass the FetchedResult from the parent view as an argument for the child view's call. And in the child view, the local FetchedResult attribute of the struct is just a stand-in for the passed in parent view FetchedResult.

But this code at the end of the instantiation of the child view seems unnecessary to me:

AddNewItemView(items: self.items).environment(\.managedObjectContext, self.managedObjectContext)