Unable to understand NSError / NSObject pointer passing behavior

Now pointers to pointers confuse me, although I read Why does NSError need double indirection? (pointer to pointer) and NSError * vs NSError ** and much more.

I thought and still asked a few questions.

Here I wrote the following:

NSError *error = [NSError errorWithDomain:@"before" code:0 userInfo:nil]; NSLog(@"outside error address: %p", &error]; [self doSomethingWithObj:nil error:&error]; 

To test the above NSError method, I wrote the following:

 - (id)doSomethingWithObj:(NSObject *)obj error:(NSError *__autoreleasing *)error { NSLog(@"inside error address: %p", error); id object = obj; if (object != nil) { return object; } else { NSError *tmp = [NSError errorWithDomain:@"after" code:0 userInfo:nil]; *error = tmp; return nil; } } 

But I found that the two registration addresses are different. Why is this?

 2016-08-19 19:00:16.582 Test[4548:339654] outside error address: 0x7fff5b3e6a58 2016-08-19 19:00:16.583 Test[4548:339654] inside error address: 0x7fff5b3e6a50 

Shouldn't they be the same since it was just a simple copy of the meaning? If they should be different, how does a pointer to a pointer eventually point to the same NSError instance?

+6
source share
2 answers

The variable in the caller is of type NSError* . The address is of type NSError* * . The function expects NSError* __autoreleasing * . Therefore, the compiler creates a hidden variable of the type NSError* __autoreleasing , copies NSError* to the hidden variable before the call, and copies it after the call to get the semantics of the __autoreleasing right.

+4
source

So, after initialization in the first line, error is a pointer to an NSError object.

In the first log, you register the address where this pointer is held. This is the effect of the operator and operator address. In any case, this address is passed to the doSomething method.

You go through: pointer -> pointer -> nserror-object.

But notice the double indirection in the doSomething signature. Auto-implement annotations make it difficult to detect, but its NSError ** .

So, the compiler takes your parameter and "expands" it twice.

It starts as a pointer -> pointer -> nserror-object. Then, after the first indirectness, it becomes a pointer β†’ nserror-object. Then after the second indirection, it becomes an nserror object.

Ergo, you register two different things. The first is the address of the pointer to the nserror object. The second is the address of the nserror object itself.

EDIT: @MANIAK_dobrii indicates that the object pointed to by error is itself different in before and after.

It's true. If an error occurs in doSomething, it creates an entirely new instance of NSError in the else clause. Then it loads it back into the error pointer. This is why you see two different addresses, after which the error pointer points to another whole object.

0
source

All Articles