iOS Gotcha: Empty NSArray Optimization

I got bitten by a little iOS optimization the other day. It turns out, that NSArray has been optimized to represent the empty array with the same singleton object, no matter how instantiated.

This code:

NSArray *a1 = [[NSArray alloc] init];
NSArray *a2 = [[NSArray alloc] init];
NSLog(@"a1 == a2 => %d", (a1 == a2));

says:

a1 == a2 => 1

which indicates, that even though it looks like we instantiate 2 objects, the “a1″ and “a2″ variables point to the same object.

It doesn’t matter much how we instantiate the empty NSArray. We could also do:

NSArray *emptyArr = [[NSArray alloc] init];
NSArray *a1 = [NSArray arrayWithArray:emptyArr];
NSArray *a2 = [NSArray arrayWithArray:emptyArr];

// or

NSArray *a1 = [NSArray array];
NSArray *a2 = [NSArray array];

// or

NSArray *a1 = [NSArray arrayWithObjects:nil];
NSArray *a2 = [NSArray arrayWithObjects:nil];

I guess it is because NSArray is immutable, that this optimization was found okay to make. If I add just one object, I can’t reproduce it. So this:

NSArray *a1 = [NSArray arrayWithObject:@"foo"];
NSArray *a2 = [NSArray arrayWithObject:@"foo"];
NSLog(@"a1 == a2 => %d", (a1 == a2));

yields:

a1 == a2 => 0

and maybe more surprising, this code:

NSArray *a1 = [NSArray arrayWithObject:@"foo"];
NSArray *a2 = [NSArray arrayWithArray:a1];
NSLog(@"a1 == a2 => %d", (a1 == a2));

also yields:

a1 == a2 => 0

I would’ve guessed, that “[NSArray arrayWithArray:a1]” simply returned “a1″, because after all, NSArray is immutable. But it seems not to, when the given array isn’t an empty array.

Anyways, I got bitten because I had some code in a setter method with an optimization that went something like this:

if (_ivarArray != newArray) {
   // work the magic
}

and I really wanted to “work the magic”, even though “_ivarArray” previously also was an empty array.

October 28, 2011 В· polesen В· No Comments
Tags:  В· Posted in: Programming

Leave a Reply