How to use Core Data's ManagedObjectModel inside a framework?

flohei picture flohei · Aug 1, 2014 · Viewed 13.1k times · Source

I'm trying to migrate a specific part of one of my apps into a framework so that I can use it in my app itself and in one of those fancy new iOS 8 widgets. This part is the one that handles all my data in Core Data. It's pretty straight forward to move everything over and to access it. I'm just having trouble accessing my momd file in there.

When creating the NSManagedObjectModel I still try to load the momd as illustrated in Apple's code templates:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyApp" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

Unfortunately, modelURL stays nil and thus MyApp crashes when accessing the Core Data stack with this error:

2014-08-01 22:39:56.885 MyApp[81375:7417914] Cannot create an NSPersistentStoreCoordinator with a nil model
2014-08-01 22:39:56.903 MyApp[81375:7417914] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Cannot create an NSPersistentStoreCoordinator with a nil model'

So, what's the right way to do this when working inside a framework with Core Data?

Answer

Jonathan Zhan picture Jonathan Zhan · Nov 1, 2015

I'm a bit late for flohei's issue, but hopefully this helps anybody else who wanders by. It is possible to get this to work without having to perform script-fu to copy resources around!

By default Apple's Core Data template gives you something like this:

lazy var managedObjectModel: NSManagedObjectModel = {
  let modelURL = NSBundle.mainBundle().URLForResource("MyCoreDataModel", withExtension: "momd")!
  return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

That would load your Core Data resources out of the main bundle. The key thing here is: if the Core Data model is loaded in a framework, the .momd file is in that framework's bundle. So instead we just do this:

lazy var managedObjectModel: NSManagedObjectModel = {
    let frameworkBundleIdentifier = "com.myorg.myframework"
    let customKitBundle = NSBundle(identifier: frameworkBundleIdentifier)!
    let modelURL = customKitBundle.URLForResource("MyCoreDataModel", withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

That should get you up and running.

Credit: https://www.andrewcbancroft.com/2015/08/25/sharing-a-core-data-model-with-a-swift-framework/