Coocoo4Cocoa Coocoo4Cocoa - 3 months ago 22
C Question

Why does NSError need double indirection? (pointer to a pointer)

This concept seems to trouble me. Why does an NSError object need its pointer passed to a method that is modifying the object? For instance, wouldn't just passing a reference to the error do the same thing?

NSError *anError;
[myObjc doStuff:withAnotherObj error:error];


and then in doStuff:

- (void)doStuff:(id)withAnotherObjc error:(NSError *)error
{
// something went bad!
[error doSomethingToTheObject];
}


Why doesn't the above work like most other object messaging patterns work? Why must instead we use error:(NSError **)error?

Answer

The NSError** pattern is used when a method normally returns some value but instead may need to return an error object (of type NSError*) if it fails. In Objective-C a method can only return one type of object, but this is a case where you want to return two. In C-like languages when you need to return an extra value you ask for a pointer to a value of that type, so to return an NSError* you need an NSError** parameter. A more realistic example would be this:

// The method should return something, because otherwise it could just return
// NSError* directly and the error argument wouldn't be necessary
- (NSArray *)doStuffWithObject:(id)obj error:(NSError **)error
{
  NSArray *result = ...;  // Do some work that might fail
  if (result != nil) {
    return result;
  } else {
    // Something went bad!
    // The caller might pass NULL for `error` if they don't care about
    // the result, so check for NULL before dereferencing it
    if (error != NULL) {
      *error = [NSError errorWithDomain:...];
    }
    return nil;  // The caller knows to check error if I return nil
  }
}

If you only had an NSError* parameter instead of an NSError** then doStuff would never be able to pass the error object back to its caller.