core data in a static library for the iPhone
Solution 1:
Sascha's answer got me on the right track. Merging a compiled .mom
file from a static library into the .mom
file from a host project was relatively simple. Here's a trivial example:
Create a new XCode Static Library project called
MyStaticLibrary
Create an .xcdatamodel file in
MyStaticLibrary
calledMyStaticLibraryModels.xcdatamodel
, add someEntity
s, then generate the headers and implementations. When you build theMyStaticLibrary
target, you'll generate alibMyStaticLibrary.a
binary file, but it won't include the compiled.mom
file. For that we have to create a bundle.Create a new build target of type
Loadable Bundle
, found underMacOS X > Cocoa
, let's call the new TargetMyStaticLibraryModels
.Drag
MyStaticLibraryModels.xcdatamodel
into theCompile Sources
build phase of theMyStaticLibraryModels
Target. When you build theMyStaticLibraryModels
Target, you will generate a file calledMyStaticLibraryModels.bundle
and it will contain the compiledNSManagedObjectModel
file,MyStaticLibraryModels.mom
.After building both the
MyStaticLibrary
andMyStaticLibraryModels
Targets, draglibMyStaticLibrary.a
(along with any associated Model header files) andMyStaticLibraryModels.bundle
into your host project,MyAwesomeApp
.MyAwesomeApp
usesCoreData
, has it's own.xcdatamodel
file which will get compiled into a .mom file during its own build process. We want to merge this.mom
file with the one we imported inMyStaticLibraryModels.bundle
. Somewhere in theMyAwesomeApp
project, there is a method that returnsMyAwesomeApp
sNSManagedObjectModel
. The Apple generated template for this method looks like this:
...
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyAwesomeApp" withExtension:@"momd"];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
We will alter this to merge and return BOTH of our NSManagedObjectModel
s, MyAwesomApp
s and MyStaticLibraryModels
, as a single, combined NSManagedObjectModel
like so:
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSMutableArray *allManagedObjectModels = [[NSMutableArray alloc] init];
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyAwesomeApp" withExtension:@"momd"];
NSManagedObjectModel *projectManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
[allManagedObjectModels addObject:projectManagedObjectModel];
[projectManagedObjectModel release];
NSString *staticLibraryBundlePath = [[NSBundle mainBundle] pathForResource:@"MyStaticLibraryModels" ofType:@"bundle"];
NSURL *staticLibraryMOMURL = [[NSBundle bundleWithPath:staticLibraryBundlePath] URLForResource:@"MyStaticLibraryModels" withExtension:@"mom"];
NSManagedObjectModel *staticLibraryMOM = [[NSManagedObjectModel alloc] initWithContentsOfURL:staticLibraryMOMURL];
[allManagedObjectModels addObject:staticLibraryMOM];
[staticLibraryMOM release];
managedObjectModel_ = [NSManagedObjectModel modelByMergingModels:allManagedObjectModels];
[allManagedObjectModels release];
return managedObjectModel_;
}
This will return the merged NSManagedObjectModel
with the Entity
s from both MyAwesomeApp
and MyStaticLibrary
.
Solution 2:
I also created my own static library that uses Core Data. Besides the static library I have a another bundle target in the project where I have a Copy Bundle Resources item, that copies some images and things like that into the bundle and a Compile Sources build phase, where I am compiling the xcdatamodel.
The final bundle will contain all the necessary files. In your main project that relies on the static library you have to include that bundle as well. Your main project will now have access to the mom file that is needed to use core data.
To use core data with the mom from the bundle you have to create a merged managed object model in your code (it might be the main project has some core data model as well):
- (NSManagedObjectModel *) mergedManagedObjectModel
{
if (!mergedManagedObjectModel)
{
NSMutableSet *allBundles = [[[NSMutableSet alloc] init] autorelease];
[allBundles addObjectsFromArray: [NSBundle allBundles]];
[allBundles addObjectsFromArray: [NSBundle allFrameworks]];
mergedManagedObjectModel = [[NSManagedObjectModel mergedModelFromBundles: [allBundles allObjects]] retain];
}
return mergedManagedObjectModel;
}
By just including the bundle you will not have to give out the xcdatamodel, only the compiled mom file needs to be included.
Solution 3:
i have some library with coredata too. i have found this template for manage a framework with embed ressources
it's really simple to use on a new project ( more difficult to apply on existing ) but for framewoks build, it's really cool :-)
https://github.com/kstenerud/iOS-Universal-Framework
Solution 4:
Sascha Konietzke's solution works well, but there is one important caveat that needs to be provided for it to work. The bundle containing the model needs to be loaded first, otherwise it will not be included in the array and merged in the MOM.
In his case he has probably already accessed resources from the bundle therefore the bundle was already loaded prior to this code being executed.
Solution 5:
Prairiedogg's answer is a little outdated, here's a tutorial on doing this in Xcode 5: http://bharathnagarajrao.wordpress.com/2014/02/14/working-with-core-data-in-a-static-library/