I've built a static library that makes heavy use of the Core Data framework. I can successfully use the library in my external project, but ONLY if I include the .xcdatamodel file in the main project. That is less than ideal, since the point of the library was to hide implementation details to the maximum possible.
In a separate question, I was informed that I cannot bundle resources with a library (which makes complete sense to me now).
So is there a way to programatically allow the model to be 'discovered' without having to include the model in the main project?
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
called MyStaticLibraryModels.xcdatamodel
, add some Entity
s, then generate the headers and implementations. When you build the MyStaticLibrary
target, you'll generate a libMyStaticLibrary.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 under MacOS X > Cocoa
, let's call the new Target MyStaticLibraryModels
.
Drag MyStaticLibraryModels.xcdatamodel
into the Compile Sources
build phase of the MyStaticLibraryModels
Target. When you build the MyStaticLibraryModels
Target, you will generate a file called MyStaticLibraryModels.bundle
and it will contain the compiled NSManagedObjectModel
file, MyStaticLibraryModels.mom
.
After building both the MyStaticLibrary
and MyStaticLibraryModels
Targets, drag libMyStaticLibrary.a
(along with any associated Model header files) and MyStaticLibraryModels.bundle
into your host project, MyAwesomeApp
.
MyAwesomeApp
uses CoreData
, 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 in MyStaticLibraryModels.bundle
. Somewhere in the MyAwesomeApp
project, there is a method that returns MyAwesomeApp
s NSManagedObjectModel
. 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
.