Why does NSError need double indirection? (pointer to a pointer)
Solution 1:
Quite simply:
if you pass a pointer to an object to your function, the function can only modify what the pointer is pointing to.
if you pass a pointer to a pointer to an object then the function can modify the pointer to point to another object.
In the case of NSError, the function might want to create a new NSError object and pass you back a pointer to that NSError object. Thus, you need double indirection so that the pointer can be modified.
Solution 2:
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.
Solution 3:
An old question, but still I think its worth putting this here -
The actual culprit is NSError. If you look at its class reference, there are no setter methods for any of its attributes, i.e. domain, code or userInfo. So there is no way, you can just alloc and initialize a NSError, pass it to the method and then populate information on the passed NSError object. (Had there been a setter method, we could have just passed a NSError * and done something like error.code = 1 in the method.)
So in case there is an error, you have to generate a new NSError object in the method and if you are doing so the only way to pass it back to the caller is by having a NSError ** argument. (For the reason explained in the above answers.)
Solution 4:
Alternate statement of what n8gray said:
Because you're not receiving an object to send messages to; you're creating the object and returning it. You generally need the pointer-to-an-NSError *
-variable argument because you can only use the return
statement on one thing at a time, and you're already using it with NO
.