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?
The model resource is no longer accessible via the
mainBundle
, you need to usebundleForClass:
like so: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:
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:
That should get you up and running.
Credit: https://www.andrewcbancroft.com/2015/08/25/sharing-a-core-data-model-with-a-swift-framework/
If you try to have core data in your framework do like this.
in YourFramework - add new file / core data / Data model ... - create all object ....
When creating new project that will use YourFramework be sure that core data is on
This will create all boiler plate inside AppDelegate.
in Test project - add Framework - add Framework as embedded framework - DELETE .xcdatamodeld file - in AppDelegate :
change
- (NSManagedObjectModel *)managedObjectModel
method into :where
YourFramework bundle id
is Bundle Identifier of YourFramework (in General / Bundle Identifier)and
Model
is name of your .xcdatamodeld file in YourFrameworkThis works.
Hope it helps.
I assume you only require the data model.
If so, I find the following is consistently the most successful method for copying across a data model file from one project to another...
.xcdatamodeld
file that reside in the target project.Close Xcode.
Using Finder (or cmd line);
.xcdatamodeld
file..xcdatamodeld
file.Move the copy of the original
.xcdatamodeld
file to your target project.Then...
.xcdatamodeld
file to your project..xcdatamodeld
file (if necessary) using Project Navigator.Does this help?
You need to drag the xcdatamodeld file and drop it in the Build Phases | Compile Sources for the targets that use the framework. Then when the target runs its [NSBundle mainBundle] will contain the model (momd file).
I may be a little late with answering this, but here's what solved my issue:
With my framework I'm delivering also a bundle with resources like images and other stuff. Putting xcdatamodeld file there didn't give anything as this file being built with the project and as a result you get a momd folder in your app bundle (which actually is missing in our case).. I have created another target, not framework, but app, built it and copied the momd from its app bundle to my separate bundle in the project (the one that goes with framework). After doing this you just need to change your resource url from main bundle to the new one:
Worked fine for me. The only thing I'm aware of is App Store Review which I didn't get to yet. So if you've found a better solution, please share.
EDIT
Found better solution. You can build the model yourself. From Core Data Programming Guide:
By "/Developer/usr/bin/" they mean "/Applications/Xcode.app/Developer/usr/bin/"
You can add a script in you target scheme and compile this automatically before each build (or after, don't think it matters). This is in case if you change the model during development.
Something like this: