Sunday, November 1, 2009

NSError

In Cocoa, objects are almost always "instantiated" in the same way. We get back a pointer to the object instead of the thing itself:

NSArray *A = [NSArray arrayWithObject:@"x"];

NSError is a little different. For example here we did this:

NSError *e;
s = [NSString
stringWithContentsOfFile:fn
encoding:NSASCIIStringEncoding
error:&e];


In the NSString Class Reference it looks like this:

+ (id)
stringWithContentsOfFile:(NSString *)path
encoding:(NSStringEncoding)enc
error:(NSError **)error


So, what's with NSError **, and what's with &e ? And what does the NSError object actually contain when an error occurs?

NSError inherits from NSObject so it can't be that complicated. Almost invariably you do not actually create an NSError object. Instead, you declare the variable, and then pass it into a method which fills it out for you if an error occurs. The NSError object is a member of a real Cocoa class, with methods and everything.

In the first function above: NSError *e; looks normal.

In error:&e the "address-of operator" & means that we are passing in the address of our pointer to the NSError object, rather than the pointer itself , as we would usually do. (On second thought, when would we ever do anything but send a message to an object?)

So, this is a pointer-to-a-pointer kind of thing, but constructed using "&". I learned about this in C++, but it does actually exist in C.

In the class reference code, the variable is an NSError **, that is, a pointer-to-a-pointer.

I'm not sure why this it's done this way. It kind of reminds me of "Handles"---old time Apple stuff that I remember from the book "Inside Macintosh."

As for what messages NSError object responds to, it may respond to:

• domain (returns a string)
• code (returns an integer that may be used as an enumerated type)
• userInfo (returns a dictionary that is often empty)

So, the sky's the limit for what can be there.


// gcc -o test test.m -framework Foundation -fobjc-gc-only
// ./test
#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
NSString *fn = NSHomeDirectory();
fn = [fn stringByAppendingString:
@"/Desktop/x.txt"];
NSError *e;
NSString *s;
s = [NSString stringWithContentsOfFile:fn
encoding:NSASCIIStringEncoding
error:&e];
NSLog(@"domain = %@", [e domain]);
NSLog(@"code = %u", [e code]);
NSLog(@"userInfo = %@", [e userInfo]);
}



$ gcc -o test test.m -framework Foundation -fobjc-gc-only
$ ./test
domain = NSCocoaErrorDomain
code = 260
userInfo = {
NSFilePath = "/Users/te/Desktop/x.txt";
NSUnderlyingError = "Error
Domain=NSPOSIXErrorDomain Code=2
\"The operation couldn\U2019t be completed.
No such file or directory\"";
}