views:

709

answers:

2

I was doing a rather ordinary addPersistentStore to an NSPersistentStoreCoordinator, and it generated an &error code.

So I went to NSLog it, and got an access error when I did this:

    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

which seems to be the common idiom.

When I reformatted the error statement as follows:

     NSLog(@"Unresolved error   %@",   [error userInfo]);

...the problem went away.

Even NSZombie didn't trap the bad access error correctly!

Any ideas?

+3  A: 

How are you catching the error?

The correct way, as described by bbum, is:

NSError *error;
BOOL success = [blah blah:blah error:&error];
if (!success) {
 NSLog(@"Error: %@ %@", error, [error userInfo]); //Or other error handling (e.g., [NSApp presentError:error]).
} else {
 //Succeeded—ignore the error variable entirely
}

(That's for a method blah:error:that returns a BOOL; the example in the question bbum answered was for a method that returned an object. The error-handling pattern is the same for both cases.)

According to his Twitter updates shortly afterward, some APIs will output an error object under the hood even if what you asked for succeeded, which means that testing the error variable instead of the BOOL return can fool you. I think this is what happened to you.

The solution is to only look at the error object if the API reports failure.

Peter Hosey
A: 

Do not forget to init NSError with nil value

NSError* err = nil;
[anObject doSomethingGetError:&err];
if (err) {
    NSLog(...);
}

If that does not help, it is API bug

vaddieg
That won't help if the API clobbers your `nil` initializer with an invalid (or valid but meaningless) object. See my answer and the tweet from @bbum that it cites.
Peter Hosey
API won't touch "err" reference [which is nil] if there is no any error. - (NSPersistentStore *)addPersistentStoreWithType:(NSString *)storeType configuration:(NSString *)configuration URL:(NSURL *)storeURL options:(NSDictionary *)options error:(NSError **)error;This method return is not BOOL type
vaddieg
Actually, setting the err object to nil only indicates that you are interested in examining the err object if one should occur. @Peter Hosey's answer shows the correct way to determine if a method call was successfull or not.
Elise van Looij
@vaddieg You can generally tell from the return value if the call was successfull, the docs are always clear about this. E.g. in this case: "The newly-created store or, if an error occurs, nil.".
Adrian
vaddieg: No, that is not correct. Again, see the tweet from @bbum that I cited in my answer. Some APIs *do* write to the error variable (thereby clobbering the `nil` you initialized it with) even if the API succeeds by the time it returns.
Peter Hosey
@vaddieg API *may* touch the err in the success case.
bbum
@Peter Hosey: Please give me a sample of method that clobbering ref to some wrong value on method success.I using Cocoa since 2002 and never has problem with NSError
vaddieg
bbum would be more likely to have an example of that case; I've never seen it myself, either. But the documentation explicitly says “you should always check that the return value is `nil` or `NO` *before* attempting to do anything with the NSError object.” (emphasis mine). http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html#//apple_ref/doc/uid/TP40001806-CH204-SW1
Peter Hosey
Apologies, I got the = nil thing backwards in my earlier comment. Apple's <a href="http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/CodingGuidelines/Articles/FrameworkImpl.html#//apple_ref/doc/uid/20001286">Coding Guidelines for Cocoa</a> >> Tips and Techniques for Framework Developers >> Exceptions and Errors states "The method should also observe the convention that all by-reference arguments are optional and thus allow the sender to pass NULL for the error-code argument if they do not wish to know about the error."
Elise van Looij
Well, interesting, in @Peter Hosey's link it says "If a method such as this encounters an error in its implementation, it directly returns NO to indicate failure and indirectly returns (if the client code requests it) an NSError object in the last parameter to describe the error.If you want to evaluate the error, declare an NSError object variable before calling a method such as writeToURL:ofType:error:. When you invoke the method, pass in a pointer to this variable. (If you are not interested in the error, just pass NULL.)"
Elise van Looij