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

This concept bothers me. Why does an NSError object need a pointer passed to a method that modifies the object? For example, is it not easy to pass a link to an error, do the same?

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

and then in doStuff:

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

Why does this not work, like most other object exchange templates? Why should we use the error: (NSError **) instead?

+43
c pointers objective-c cocoa
May 24 '09 at 4:53
source share
5 answers

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

 // 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 had only the NSError* parameter instead of NSError** , then doStuff never pass the error object back to its caller.

+75
May 24 '09 at 5:07
source share

Pretty simple:

if you pass a pointer to an object of your function, the function can only change what the pointer points to.

if you pass a pointer to a pointer to an object, then the function can change the pointer to point to another object.

In the case of NSError, the function may want to create a new NSError object and pass you a pointer to this NSError object. So you need double indirection so that you can change the pointer.

+89
May 24 '09 at 6:02 a.m.
source share

Alternative output of what n8gray said:

Because you are not receiving an object for sending messages; you create an object and return it. Usually you need the argument pointer-to-an- NSError * -variable, because you can use the return only once at a time, and you already use it with NO .

+6
May 24 '09 at 5:52 a.m.
source share

An old question, but still I think it's worth putting it here -

The actual culprit is NSError . If you look at its class reference, there are no configuration methods for any of its attributes, such as a domain, code, or user information. Thus, there is no way, you can simply assign and initialize an NSError, pass it to the method, and then populate the information about the passed NSError object. (If there was a setter method, we could just pass NSError * and do something like error.code = 1 in the method.)

So, if an error occurs, you must generate a new new NSError object in the method, and if you do this, the only way to pass it back to the caller is the NSError ** argument. (For the reasons stated in the answers above.)

+6
Jan 28 '14 at 6:16
source share

I still haven't gotten the full picture by reading all the answers above. The layman lesson that I did below helped me understand what was going on. Just put it there if it helps other newbies.

Suppose you have the following

 @interface Class X -(void) methodX:(NSMutableArray *)array; @end 

In some other part of the code, you have the following sequence

 ClassX *objectX = [[ClassX alloc] init]; NSMutableArray *arrayXX = [@[@(1), @(2)] mutableCopy]; //What is stored in arrayXX is the address in the heap at which the NSMutableArray object starts, lets call this address ZZZ //array starting at address ZZZ in the heap now contains NSNUmbers @1,@2 [objectX methodX:array] 

When you call [objectX methodX:array] , what the method gets is a copy of array . Since the array contains an address (i.e., Pointer), the copy is special in that what is received is another variable with the ZZZ address in it.

So, if methodX does [array removeObjectAtIndex:0] , then the object starting with the ZZZ address is exposed (now it contains only one NSNUmber @ (2)). Thus, when the method returns, the original array is also exposed.

Suppose that instead of method X does array = [@[@(2)] mutableCopy]; the original array will not be affected. This is because you have not entered the ZZZ address and changed something. Instead, you copied ZZZ in the copy obtained by the method to another YYY address. The YYY address is the start of an NSMUtableArray with one NSNUmber @ (2) element. The ZZZ source address still contains an NSMUtableArray with two elements. @ (1) and @ (2). That way, when the method returns, the original array does not change.

0
Aug 12 '16 at 6:35
source share



All Articles