0

when I test method "retainCount", I met a question, just as below:

NSString *s_afmt0 = [[NSString alloc] initWithFormat:@""]; //-1
NSString *s_afmt1 = [[NSString alloc] initWithFormat:@"123"]; //1
NSLog(@"s_afmt0:%d", [s_afmt0 retainCount]);
NSLog(@"s_afmt1:%d", [s_afmt1 retainCount]);

result : s_autf0:-1 s_autf1:1 I don't know why? why s_afmt0's retainCount is -1, and s_autf1's retainCount is 1. What is the difference between @"" and @"123"? anyone can explain ? thanks

expl
  • 33
  • 5

2 Answers2

9

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

yfrancis
  • 2,616
  • 1
  • 17
  • 26
  • do you mean NSUIntegerMax for retainCount indicating static objects? It's not exactly documented, although the recommended singleton pattern for permanent, singleton Cocoa objects has always indicated that you should override -retainCount and return NSUIntegerMax to indicate that the singleton should never be freed. – yfrancis Oct 31 '12 at 03:52
  • no worries expl, there's nothing wrong with experimenting with the Objective-C runtime, its a great learning experience. Just don't rely on something as fragile as retainCount in production code :) – yfrancis Oct 31 '12 at 03:57
  • if api is open , something is better. Maybe – expl Oct 31 '12 at 04:09
  • 1
    No -- really -- don't use `retainCount`. Not ever. Not for debugging because there are always better, more informative, tools available. And not for production, because `retainCount` doesn't actually provide useful information (doesn't reflect autorelease state nor thread issues). – bbum Oct 31 '12 at 20:12
  • 2
    bbum I'll second that, if you restrict your options to debugging and production. However, you yourself did some experiments with retainCount and blogged about it, so if all you're doing is hacking, I think its awesome to experiment and learn what you can about the platform – yfrancis Oct 31 '12 at 20:37
1

While you should never use retainCount, the most likely reason for what you are seeing is that the empty string @"" is being treated special by the compiler since it is such a common literal.

Also, why are you using string formats with string literals? I suppose this is just for testing purposes but you should just have:

NSString *s_afmt0 = @""; // no need to use stringWithFormat here
rmaddy
  • 314,917
  • 42
  • 532
  • 579