2

Why the following NSLog results are different?

UIView *view = [UIView new];
NSLog(@"%p",&view); //0x7fff59c86848
[self test:&view];

-(void)test:(UIView **)view{
   NSLog(@"%p",view); // 0x7fff59c86840
}

While the following NSLog results are same?

 NSInteger j = 1;
 NSLog(@"%p", &j);//0x7fff5edc7ff8
 [self test1:&j];

- (void)test1:(NSInteger *)j{
   NSLog(@"%p", j);//0x7fff5edc7ff8
}
Zentopia
  • 735
  • 1
  • 8
  • 14

1 Answers1

3

Good question with a non-obvious answer.

It is all to do with the ownership qualifiers associated with variables. When you declare:

NSView *view;

this is a shorthand for:

NSView __strong * view;

i.e. the reference is held strongly by the variable view.

However when you declare:

-(void)test:(UIView **)view

this is shorthand for:

-(void)test:(UIView * __autoreleasing *)view

here view is of type pointer to variable of type __autoreleasing pointer to UIView.

The reason for this difference, __strong vs. __autoreleasing, is due to what Apple term's call-by-writeback and is explained in Variable Qualifiers in Apple's "Transitioning to ARC Release Notes" and in Ownership qualification in CLANG Documentation: Automatic Reference Counting. It is also explained the SO questions Handling Pointer-to-Pointer Ownership Issues in ARC and NSError and __autoreleasing.

In brief: a pointer to __strong variable cannot be passed as a pointer to an __autoreleasing one. To support you doing this the compiler introduces a hidden temporary variable and passes its address instead. I.e. your code is effectively compiled as:

UIView *view = [UIView new];
NSLog(@"%p",&view);
UIView __autoreleasing * compilerTemp = view;
[self test:&compilerTemp];
view = compilerTemp;

Hence why you see a different address.

Community
  • 1
  • 1
CRD
  • 52,522
  • 5
  • 70
  • 86
  • Thanks, your answer is really accurate. The reverse engineering result worked as you say. And the addresses are same in MRC. – Zentopia Dec 09 '16 at 06:46