Prompted by a friend's tweet (sorry it's late Kevin!) I was reminded of the code we've implemented to make life more pleasant when Core Data throws an error your way.
Problem 1: The alert sheet doesn't reveal enough detail
It's understandable; your customers don't care which bit of the model failed validation, they want a more helpful answer supplied by the application – or even better the error not to occur in the first place! But what about you, how do you dig into the error for more detail?
One option is to place a breakpoint on -[NSApp willPresentError:]. From there, introspect the error object in the debugger.
But this is somewhat of a pain. Getting hold of the error object in the debugger is tricky for a start! Somewhat more palatable is to log such errors to the console (probably for debug builds only, but up to you).
A nice convenient location is your app delegate:
- (NSError *)application:(NSApplication *)theApplication
willPresentError:(NSError *)error
{
// Log the error to the console for debugging
NSLog(@"Application will present error:\n%@", [error description]);
return error;
}
Problem 2: There's no easy way to see the entirety of an error's contents
The above snippet uses the built-in -[NSError description] method. It's pretty informative, but Core Data has a tendency to construct several, nested error objects. Particularly if there are multiple validation errors. Try this little beauty out in a category on NSError:
- (NSString *)debugDescription;
{
// Log the entirety of domain, code, userInfo for debugging.
// Operates recursively on underlying errors
NSMutableDictionary *dictionaryRep = [[self userInfo] mutableCopy];
[dictionaryRep setObject:[self domain]
forKey:@"domain"];
[dictionaryRep setObject:[NSNumber numberWithInteger:[self code]]
forKey:@"code"];
NSError *underlyingError = [[self userInfo] objectForKey:NSUnderlyingErrorKey];
NSString *underlyingErrorDescription = [underlyingError debugDescription];
if (underlyingErrorDescription)
{
[dictionaryRep setObject:underlyingErrorDescription
forKey:NSUnderlyingErrorKey];
}
// Finish up
NSString *result = [dictionaryRep description];
[dictionaryRep release];
return result;
}
Did you know that when you do po foo in the debugger, the string printed is actually generated by calling -[foo debugDescription]? So this neatly means that po error will give you better results.
And of course, you'll want to change the error presentation snippet at the top of the page to log using -debugDescription.

