Yep, another Core Data post. Hat tip to Jeff LaMarche for the solution on this one.
After adding a new data model version, then moving some furniture around and adding a few new bits and bobs, I hit Build & Go and was hit with the fantastically detailed error:
Can't merge models with two different entities named 'SuckItBiatch'
Head on over to Jeff’s post for the full explanation of what’s going on here but to cut a long story short, there’s an issue with how the .momd bundle works in tandem with Apple’s template code.
Replace the standard -managedObjectModel method with the following, and as long as all other prerequisite pieces are in order you should be fine.
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
NSString *path = [[NSBundle mainBundle] pathForResource:@"YourAppName" ofType:@"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
return managedObjectModel;
}
if (![self.managedObjectContext save:&error]) {
NSLog(@"Error: %@", error);
}
That’s the typical, Apple-sample-code method for logging error messages in Core Data. Unfortunately, it will only give you half the story when your code mystifyingly refuses to work. To get at the detail behind those cryptic error codes supplied by NSError, I heartily recommend the following snippet from Charles on StackOverflow
:
NSError* error;
if(![[survey managedObjectContext] save:&error]) {
NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(@" DetailedError: %@", [detailedError userInfo]);
}
}
else {
NSLog(@" %@", [error userInfo]);
}
}
As explained in the accompanying post, this logs to the console all errors from the top down (particularly useful if you’re the lucky recipient of the particularly unuseful 1560 NSValidationMultipleErrorsError).
This might result in a log message like the following:
Failed to save to data store: Operation could not be completed. (Cocoa error 1570.)
{
NSLocalizedDescription = "Operation could not be completed. (Cocoa error 1570.)";
NSValidationErrorKey = theBuggeredAttribute
NSValidationErrorObject = <> (entity: AnObject; id: 0x3a04050 <> ; data: {
attribute = 0;
anotherAttribute = (
);
aThirdAttribute = 0x3ac4d10 <>;
theBuggeredAttribute = "anInvalidValue";
});
}
>>>
This gives you all the detail you need to fix your problems, but can be a bit confusing to begin with. What this message tells you is that an instance of the NSValidationErrorObject - in this case an instance of AnObject - has a validation error. The four-digit Cocoa error code gives you more information about the particular brainfart that’s had you bashing your head against the desk for the last two hours. There’s a full list on the Apple website.
You need to fix the value of the attribute indicated by NSValidationErrorKey - theBuggeredAttribute - according to the rules in your data model for the object to be saved correctly. Among other things it may be that this is a required attribute that hasn’t been set, or that the attribute has been given a value outside its specified valid range. The error I encountered that led me down this path in the first place was a mandatory relationship that I’d forgotten to set, represented by the code 1570, or to give it its Sunday name, NSValidationMissingMandatoryPropertyError.