42

I am new to core data.

What I am trying to DO: I am trying to create a cocoatouch framework that has an app to add employee details and display them in a table view. So that i can add this framework to my main project to work independently.

Issues I face: The frame work builds without any error. I have added the core data stack from swift 3 to the framework. But when i run the main project, the moment the framework loads the log displays "Failed to load model named Simple framework", "fetch failed" and "employee must have a valid entity description". The code that I have used in the framework is as shown below :

public class CoreDataStack {
    public static let sharedInstance = CoreDataStack()

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "SimpleFramework")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error {
                fatalError("Unresolved error \(error), \(error)")
            }
        })
        return container
    }()

    public func saveContext() {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch let error as NSError {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
    }
}

@IBAction func addEmployee(_ sender: Any) {

    //To save the data
    let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
    let employee = Employee(context: context)
    employee.employeeName = nameTextField.text
    employee.employeeAge = Int16(ageTextField.text!)!
    employee.hasVehicle = hasVehicle.isOn
    CoreDataStack.sharedInstance.saveContext()
    navigationController!.popViewController(animated: true)
}

@IBAction func addEmployee(_ sender: Any) {

    //To save the data
    let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
    let employee = Employee(context: context)
    employee.employeeName = nameTextField.text
    employee.employeeAge = Int16(ageTextField.text!)!
    employee.hasVehicle = hasVehicle.isOn
    CoreDataStack.sharedInstance.saveContext()
    navigationController!.popViewController(animated: true)
}

This is a screenshot of the console log.

pkamb
  • 33,281
  • 23
  • 160
  • 191
Ashiq Sulaiman
  • 631
  • 1
  • 6
  • 14

6 Answers6

125

I've had this issue, when I had wrong model name - it should be models name, not the projects (see the screen shot)enter image description here

Dmitriy Yerchick
  • 1,341
  • 1
  • 7
  • 9
61

Explicitly pass the models file name to the Core Data stack for initialization and make sure, it is loaded from the right bundle at the time (test bundle, app bundle...) by using Bundle(for: type(of: self)):

//...
let momdName = "SimpleFramework" //pass this as a parameter
//...

guard let modelURL = Bundle(for: type(of: self)).url(forResource: momdName, withExtension:"momd") else {
        fatalError("Error loading model from bundle")
}

guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
    fatalError("Error initializing mom from: \(modelURL)")
}

persistentContainer = NSPersistentContainer(name: momdName, managedObjectModel: mom)

//...

Edit:

Also make sure, the SimpleFramework.xcdatamodeld is added to the used targets Target Membership:

shallowThought
  • 19,212
  • 9
  • 65
  • 112
  • This doesn't work. I am getting error on all the guard statements. I tried rewriting the code, but it throws "consecutive statements on a line must be separated by ; ". – Ashiq Sulaiman Mar 02 '17 at 13:06
  • If it is in contained in the target and the naming is right (tripple check!), the code works in all our products. Maybe update the question with more information (show model aso.) – shallowThought Mar 02 '17 at 15:36
  • 3
    ```guard let modelURL = Bundle(for: type(of: self)).url(forResource: momdName, withExtension:"momd") else { fatalError("Error loading model from bundle") }``` Did the trick for me as I was using model inside of a dynamic library and thus bundle was no longer main. – James Matthew Mudgett Feb 12 '18 at 19:34
  • Even with the model in the expected target and the name correct when creating the NSPersistentContainer, I still got the error. But this fixed it for me! Thanks. – bdmontz Jun 13 '18 at 16:49
  • When I moved the Model out of the main app and into a Framework I saw this error and this answer fixed it for me. Thanks :) – lewis Oct 17 '19 at 11:46
  • Lifesaver! Update as of Xcode 11, Swift 5.x: The extension for the MOM-file is now `mom` and no longer `momd`! You can find the file by right-click in the Project-Navigator on your Framework-Target under products, click on "Show in Finder" and search for it. Mine was directly in the `MyFramework.framework` folder. – jboi Oct 31 '19 at 09:50
  • adding it to Target fixed the issue for me - Thanks :) – N. Der Jan 15 '20 at 08:32
  • @jboi I'm in Xcode 12, Swift 5., and the extension for the mom is still momd for me. Weird. Not sure why I need to explicitly declare the model URL and init the persistent container this way, but it works and that's what matters. Another app I have doesn't need to do this explicitly. Thanks! – Brian M Oct 13 '20 at 13:43
  • Thank you so much sir! This fixed the issue for me. – Jon_the_developer Apr 23 '21 at 21:11
11

The string you pass to the NSPersistentContainer initializer:

NSPersistentContainer(name: "CoreData")

needs to match the filename of the data model file in your Xcode project:

CoreData.xcdatamodeld
pkamb
  • 33,281
  • 23
  • 160
  • 191
4

If you want to use CoreData in your dynamic framework you have to subclass NSPersistentContainer and use it instead of NSPersistentContainer.

class PersistentContainer: NSPersistentContainer { }

//...

lazy var container: PersistentContainer = {
    let result = PersistentContainer(name: "Your xcdatamodeld file name here")
    result.loadPersistentStores { (storeDescription, error) in
        if let error = error {
            print(error.localizedDescription)
        }
    }
    return result
}()
Levan Karanadze
  • 739
  • 1
  • 11
  • 21
2

In my case, for some reason the DataModel.xcdatamodeld became missing from my project workspace.

First I tried creating a new DataModle.xcdatamodeld and recreating the data model, but the same error occurred. Thats when I realized that the Original DataModel.xcdatamodeld was still in the root directory. I fixed this by simply right clicking my project in my project navigator, and selecting "Add files to "Project"...", then I added my old data model and deleted my new data model. Finally I hard cleaned, ran my project and it fixed the issue.

2

My problem was at my .podspec file. You should include the xcdatamodeld extension on the pod that you are creating.

s.resources = "myprojectfolder/**/*.{png,jpeg,jpg,storyboard,xib,xcassets,xcdatamodeld}"
pkamb
  • 33,281
  • 23
  • 160
  • 191
mourodrigo
  • 2,232
  • 28
  • 18