you're printing the retainCount as a signed integer, when in fact it is an unsigned integer (type NSUInteger
with a format specifier of %u
, not %d
). -1 is equivalent to UINT_MAX
, and means the object has no retainCount. It is likely that NSString has recognized that the given string is immutable, and assigned the pointer to the static @"" empty NSString, rather than placing one on the heap.
In fact, you can confirm this with the following code:
NSString* str1 = [[NSString alloc] initWithFormat:@""];
NSString* str2 = [[NSString alloc] initWithFormat:@""];
NSLog(@"string1: %p, string2: %p", str1, str2);
The above code should print the same pointer address for both str1 and str2, confirming my theory that NSString optimizes this particular case out, and indeed it does:
06:46:30.142 StringTest[45214:303] string1: 0x7fff7d8acf90, string2: 0x7fff7d8acf90
So let's see if this is specific to NSString. It should be, otherwise all NSMutableString objects initialized to an empty string would point to the same memory!
NSMutableString* str1 = [[NSMutableString alloc] initWithFormat:@""];
NSMutableString* str2 = [[NSMutableString alloc] initWithFormat:@""];
NSLog(@"string1: %p, string2: %p", str1, str2);
Outputs:
06:53:36.688 StringTest[45278:303] string1: 0x10010a850, string2: 0x10010a890
Two different memory locations. So there you have it, a neat little optimization in the Foundation framework. TIL
Edit:
As bbum points out, you should never rely on retainCount, and this is an example of where things can go wrong if you do