Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

core data in a static library for the iPhone

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?

like image 389
Vik Avatar asked Nov 10 '09 22:11

Vik


People also ask

What is Core Data on iPhone?

Core Data is a framework that you use to manage the model layer objects in your application. It provides generalized and automated solutions to common tasks associated with object life cycle and object graph management, including persistence.

What is static library in iOS?

Static library - a unit of code linked at compile time, which does not change. However, iOS static libraries are not allowed to contain images/assets (only code).

Should I use Core Data iOS?

The next time you need to store data, you should have a better idea of your options. Core Data is unnecessary for random pieces of unrelated data, but it's a perfect fit for a large, relational data set. The defaults system is ideal for small, random pieces of unrelated data, such as settings or the user's preferences.

Where does Core Data store Data?

The persistent store should be located in the AppData > Library > Application Support directory. In this example you should see a SQLite database with extension . sqlite. It is possible that you don't see the persistent store in the Application Support directory.


2 Answers

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:

  1. Create a new XCode Static Library project called MyStaticLibrary

  2. Create an .xcdatamodel file in MyStaticLibrary called MyStaticLibraryModels.xcdatamodel, add some Entitys, 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.

  3. Create a new build target of type Loadable Bundle, found under MacOS X > Cocoa, let's call the new Target MyStaticLibraryModels.

  4. 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.

  5. 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.

  6. 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 MyAwesomeApps 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 NSManagedObjectModels, MyAwesomApps 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 Entitys from both MyAwesomeApp and MyStaticLibrary.

like image 131
prairiedogg Avatar answered Oct 07 '22 20:10

prairiedogg


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.

like image 28
Sascha Konietzke Avatar answered Oct 07 '22 19:10

Sascha Konietzke