When you pass a parameter into a method it is copied and later inside your method you deal with that copy:
- (void)changeA:(NSInteger)aToChange {
aToChange = 7;
}
Then, when you use that method you won't be able to change the value you passed from the inside of that method:
NSInteger a = 42;
[smb changeA:a];
// a is still 42
That's because inside -changeA:
you deal with a copy of arguments, i.e. so you do something like (pseudo code):
// inside changeA:
NSInteger aToChange = a; // (value is copied)
aToChange = 7; // this does not modify a, right?
You might even get the address of that aToChange
and try to do something with it:
// inside changeA:
NSInteger aToChange = a; // (value is copied)
NSInteger *pointerToCOPY = &aToChange; // get address of aToChange
NSInteger *pointerToA = &a; // get address of a
// here pointerToCOPY != pointerToA
So, going back to your code:
NSError *error = nil; // outer error, passed as a parameter
...
- (id)doSomethingWithObj:(NSObject *)obj error:(NSError *)error
{
// NSError *error(local copy) = error(passed argument);
error = tmp; // here error is the pointer to the local error copy
return nil;
}
As it was before with aToChange
, you can't modify your external NSError error *
from inside your method. That's why double pointers are used, you send pointer to your pointer, so that you still have access to the external error
reference and can set it.
- (id)doSomethingWithObj:(NSObject *)obj error:(NSError **)error
{
// NSError **error(local copy) = error(passed argument);
*error = tmp; // Here *error is the pointer to the local error copy,
// When you dereference error you get NSError *, which you can set,
// that's your external error.
return nil;
}
Note than it's impossible to do this:
NSError *error = nil;
NSError *otherError = [NSError error with];
*error = otherError;
error
is a pointer to a struct, *error
is a struct, the one with single isa
field (from the point of the id type defenition). It's inappropriate to assign pointer to error (otherError
, i.e. platform pointer size int) to a struct.
And then, the last question remains, why can't you:
NSError *error = nil;
NSError *otherError = [NSError error with];
*error = *otherError; // why can't I assign to structs?
I'm not completely sure, but, maybe memory management and ABI comes in the game, here it could just copy bunch of bytes from one object to another as they are just a C structs.
As you know, Objective-C is a superset of C, and it is possible to assign structs there: Assign one struct to another in C. That's Objective-C peculiarity dealing with objects, I think. Everything is pretty much dynamic, you can create classes at the runtime and add instance variables (Mike Ash on that topic), so it is not known at the compile time what is beyond the isa
field in the struct and, actually id
is just a pointer to that struct with a single isa
. That's not a good idea to just copy that single isa
struct and say you're done, things will fall apart.