executeFetchRequest return type changed when model placed in static library
I'm hoping this will be an easy one for someone with more Core Data and XCode experience than myself.
I'm trying to move the model layer of an iOS app to a static library so I can开发者_StackOverflow reuse it. I've successfully separated the code and built/run the application. Unfortunately, I'm encountering a peculiar problem.
Consider the following code snippet:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
[fetchRequest setEntity:entityDescription];
fetchRequest.includesSubentities = NO;
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"UID = %@", uID]];
fetchArray = [context executeFetchRequest:fetchRequest error:&fetchError];
id obj = [fetchArray objectAtIndex:0];
NSString *fetchArrayIndexZeroEntityName = [[obj entity] name];
When everything is in a single xcode project:
obj pointer type according to the xcode debugger hover bubble is MyCustomCoreDataClassName
and
fetchArrayIndexZeroEntityName = @"MyCustomCoreDataClassName"
After I move the core data model into a static library:
obj pointer type according to the xcode debugger hover bubble is NSManagedObject
and
fetchArrayIndexZeroEntityName = @"MyCustomCoreDataClassName"
Later in my code I make the following call:
[obj isKindOfClass:[MyCustomCoreDataClassName class]]
When everything is in a single xcode project the above call returns YES. After I move the core data model into a static library the above call returns NO.
This behavior obviously has rather dire consequences on my application. Any thoughts on what might be wrong and how to fix it? It's totally possible I linked these projects together incompletely or incorrectly even though it compiles without error and runs at least enough to uncover the above.
Thank you, Andrew
Depending on how you're setting up your Core Data stack, right down in the guts of it, check that when you read the NSManagedObjectModel(s), which normally get instantiated from an NSBundle you have some valid entities. Set a breakpoint in your project where the model returns, and then in the debugger call:
po [[managedObjectModel entitiesByName] allKeys]
If that returns the list of entities, then I'm not sure exactly what's going on, but, I suspect that it will return an empty list, because the code can't find any mom files in your project.
Here is what I did to get round this. In your static library project (or if your static library is just another target in your main project), create a new NSBundle target. Add the Core Data model and any mapping models you have to this target. Then add it as a dependency to your static library target, and the application target. In your main application target, add this new bundle into the Copy Bundle Resources build phase.
Then, in your Core Data stack, you just need to search all bundles for models. I have code a bit like this:
/**
Creates, retains, and returns the managed object model for the application
by merging all of the models found in the application bundle.
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel) return managedObjectModel;
// Get all the bundles including ones nested inside the main bundle
NSMutableSet *allBundles = [NSMutableSet set];
NSMutableSet *newBundles = [NSMutableSet set];
NSUInteger numberOfBundles = 0;
[allBundles addObject:[NSBundle mainBundle]];
while (numberOfBundles < [allBundles count]) {
// Look for nested bundles
for(NSBundle *bundle in allBundles) {
NSArray *morePaths = [NSBundle pathsForResourcesOfType:@".bundle" inDirectory:[bundle bundlePath]];
if([morePaths count] > 0) {
for(NSString *bundlePath in morePaths) {
if(![allBundles containsObject:bundlePath])
[newBundles addObject:[NSBundle bundleWithPath:bundlePath]];
}
}
}
// Add the new bundles
[allBundles unionSet:newBundles];
numberOfBundles = [allBundles count];
}
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:[allBundles allObjects]] retain];
if (managedObjectModel) return managedObjectModel;
return nil;
}
Note that the above code doesn't need to know what you've called your model. I have this function in a singleton class which also instantiates the persistent store coordinator and returns the MOC. So effectively, once you've done that you've got a totally general use anywhere Core Data stack which you can instantiate from anywhere in your application.
I guess I could post the source for this somewhere if people want it. Anyway, hope that puts you on the right track.
精彩评论