I was wondering, why this code:
NSArray *emptyArr = [[[NSArray alloc] init] autorelease];
NSArray *emptyArrA = [NSArray arrayWithArray:emptyArr];
NSArray *emptyArrB = [NSArray arrayWithArray:emptyArr];
NSLog(@"emptyArrA == emptyArrB => %d", (emptyArrA == emptyArrB));
NSLog(@"emptyArr == emptyArrB => %d", (emptyArr == emptyArrB));
NSLog(@"emptyArrA == emptyArr => %d", (emptyArrA == emptyArr));
output the following:
emptyArrA == emptyArrB => 1
emptyArr == emptyArrB => 1
emptyArrA == emptyArr => 1
that is, the objects seem to be indentical? Hmm, I thought, this must be a iOS (or CoreFoundation?) optimization on the special case of the immutable, empty NSArray, which then always resolves to the same object instance.
But…this code:
NSLog(@"emptyArr => %p", &emptyArr);
NSLog(@"emptyArrA => %p", &emptyArrA);
NSLog(@"emptyArrB => %p", &emptyArrB);
outputs (on my machine):
emptyArr => 0xbfffdd64
emptyArrA => 0xbfffdd60
emptyArrB => 0xbfffdd5c
which to me indicates 3 different instances.
How come the “==” operator then tell me they are identical objects?
Is it clever compiler optimzations?
–UPDATE–
Given the below answers, I’m still a bit confused :-). I’ll expand a bit on my question here..
The answers tell me, that “&arrayObject” takes the address of the variable, as opposed to the object, and I guess this code tells me that to be true:
NSLog(@"emptyArr => %p", &*emptyArr);
NSLog(@"emptyArrA => %p", &*emptyArrA);
NSLog(@"emptyArrB => %p", &*emptyArrB);
because it outputs:
emptyArr => 0x6829fd0
emptyArrA => 0x6829fd0
emptyArrB => 0x6829fd0
which indicates the same object. But this indicates (to me at least), that there is some kind “magic” in the “==” operator for NSObject instances, that actually make it compare pointers to the objects behind the variable instead of pointers to the variabel. Is that correct?
Because, if I do the same thing with an “int*”, I must dereference it to get equality. Like this:
int *i1 = malloc(sizeof(int));
*i1 = 42;
int *i2 = malloc(sizeof(int));
*i2 = 42;
NSLog(@"i1 == i2 => %d", (i1 == i2));
NSLog(@"*i1 == *i2 => %d", (*i1 == *i2));
which gives me:
i1 == i2 => 0
*i1 == *i2 => 1
which is also what I would expect from my (somewhat dated) C experiences 🙂
?
Your second test takes the address of the variables, and correctly indicates that there are three different variables. All three variables point to the same empty array instance — as an optimization, NSArray always returns the same empty array, and
arrayWithArray:on NSArrays just retains the argument, since it is immutable and thus they’re indistinguishable anyway. If you want to see that, take out the&operator in all of your log statements. If you had tested&emptyArrA == &emptyArrB, you would have seen that false too.To answer your new question: No, there’s no magic. It’s just normal pointer equality. When you write
somePointer == someOtherPointer, it always tells you whether they point to the same address, regardless of type —int,BOOL,NSMutableAttributedString*, any type. It compares the addresses stored in the pointers. It will never compare magically pointers to the pointers.I think what you’re missing is that objects are always referenced by pointers — they are never direct values like ints. To test objects for value equality rather than pointer equality, you need a method like
isEqual:.