Hardy
Hardy

Reputation: 4796

entityForName: nil is not a legal NSPersistentStoreCoordinator for searching for entity name

I set up a DatabaseApplicationService that

This all works fine, as it seems.

    lazy var persistentContainer: NSPersistentCloudKitContainer = {

        // Ensure that we have the required path.
        pathHandler.ensurePersistentStorePath()

        #if DEBUG
        // get the store description
        guard let description = container.persistentStoreDescriptions.first
            else {
                fatalError("Could not retrieve a persistent store description.")
            }

        // initialize the CloudKit schema
        try? container.initializeCloudKitSchema(options: NSPersistentCloudKitContainerSchemaInitializationOptions.dryRun)

        #endif

        let local = NSPersistentStoreDescription(url: pathHandler.persistentLocalStoreURL)
        local.configuration = "Local"

        let cloud = NSPersistentStoreDescription(url: pathHandler.persistentCloudStoreURL)
        cloud.configuration = "Cloud"

        cloud.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.com.innoreq.HappyFreelancer")
        container.persistentStoreDescriptions = [ local, cloud ]

        container.loadPersistentStores(completionHandler: { (storeDescription, error) in

            if let error = error as NSError? {

                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                Typical reasons for an error here include:
                * The parent directory does not exist, cannot be created, or disallows writing.
                * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                * The device is out of space.
                * The store could not be migrated to the current model version.
                Check the error message to determine what the actual problem was.
                */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

In the SceneDelegate, the environment gets the NSManagedObjectContext injected:

        let contentView = ContentView().environment(\.managedObjectContext, databaseService.context)

In the view's model, the environment is asked for the context:

    @Environment(\.managedObjectContext) var managedObjectContext: NSManagedObjectContext

Now, when fetching data from the context:

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "EWork")

        do {

            return try managedObjectContext.execute(fetchRequest) as! [IsTimedAndTagged]
        } catch {

            fatalError("Failed to fetch EWork")
        }

this error is thrown at runtime:

2020-01-23 16:34:05.981483+0100 XY[14121:20859222] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSPersistentStoreCoordinator for searching for entity name 'EWork''

When checking the service's coordinator, it is not nil. Is there any explanation for that strange effect?

Upvotes: 5

Views: 3712

Answers (2)

wei
wei

Reputation: 4727

I had the same error when I tried to create a new NSManagedObject in a child context but the child context didn't have a persistent store assigned.

The code produces the error:

let childContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) // The context doesn't have related persistent store
let newObject = NSEntityDescription.insertNewObject(forEntityName: entityName, into: childContext) // The error occurred when trying to find the entity from a nil persistent store

Adding the persistent store to the child context fixed the error.

@Environment(\.managedObjectContext) var moc
let childContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
childContext.persistentStoreCoordinator = moc.persistentStoreCoordinator // add persistent store to the context

let newObject = NSEntityDescription.insertNewObject(forEntityName: entityName, into: childContext) 

Reference: https://blog.csdn.net/weixin_40200876/article/details/87866492

Hope it helps :)

Upvotes: 1

Siddharth Choudhary
Siddharth Choudhary

Reputation: 1129

For those who are using Swift5 and doesn't have Appdelegate in there and trying to create NFSRequest queries.

You might be missing the persistent store and so creating your own custom store might work. Cause that was my issue.

Creating your own PersistentContainer class:

import SwiftUI
import CoreData
@main
struct TestApp: App {
        let context = PersistentCloudKitContainer.persistentContainer.viewContext
        var body: some Scene {
                WindowGroup {
                        ContentView().environment(\.managedObjectContext, context)
                }
        }
}

Then your custom class like this:

import CoreData
public class PersistentCloudKitContainer {
        // MARK: - Define Constants / Variables
        public static var context: NSManagedObjectContext {
                return persistentContainer.viewContext
        }
        // MARK: - Initializer
        private init() {}
        // MARK: - Core Data stack
        public static var persistentContainer: NSPersistentContainer = {
                let container = NSPersistentContainer(name: "Model")
                container.loadPersistentStores(completionHandler: { (storeDescription, error) in
                        if let error = error as NSError? {
                                fatalError("Unresolved error \(error), \(error.userInfo)")
                        }
                })
                container.viewContext.automaticallyMergesChangesFromParent = true
                container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
                return container
        }()
        // MARK: - Core Data Saving support
        public static func saveContext () {
                let context = persistentContainer.viewContext
                if context.hasChanges {
                        do {
                                try context.save()
                        } catch {
                                let nserror = error as NSError
                                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                        }
                }
        }
}

Hope it helps someone like me, who might end up here looking for answers!

Upvotes: 2

Related Questions