Why has NSNumber such strange retainCounts?

NSNumber* n = [[NSNumber alloc] initWithInt:100];
NSNumber* n1 = n;

In the code above, why is the value of n’s retainCount set to 2? In the second line of the code, I didn’t use retain to increase the number of retainCount.


I found a strange situation. Actually the retainCount depends on the initial number:

  • How to check if downloaded PNG image is corrupt?
  • Detecting the use of private APIs
  • iOS5 UITapRecognizer for UIScrollView interfering with buttons. How to fix?
  • Is there a way the Round Rect button to take exactly the same size of an image?
  • iOS Minimum OS Requirements different between Xcode project and iTunes Connect
  • How do I add custom UIButton to nib file in XCode?
  • NSNumber *n = [[NSNumber alloc] initWithInt:100]; 
    // n has a retainCount of 1
    
    NSNumber *n2 = [[NSNumber alloc] initWithInt:11]; 
    // n has a retainCount of 2
    

    5 Solutions Collect From Internet About “Why has NSNumber such strange retainCounts?”

    Based on this link here, it’s possible that there’s some optimization going on under the covers for common NSNumbers (which may not happen in all implementations hence a possible reason why @dizy’s retainCount is 1).

    Basically, because NSNumbers are non-mutable, the underlying code is free to give you a second copy of the same number which would explain why the retain count is two.

    What is the address of n and n1? I suspect they’re the same.

    NSNumber* n = [[NSNumber alloc] initWithInt:100];
    
    NSLog(@"Count of   n : %i",[n retainCount]);
    
    NSNumber* n1 = n;
    
    NSLog(@"Count of   n : %i",[n retainCount]);
    NSLog(@"Count of   n1: %i",[n1 retainCount]);
    NSLog(@"Address of n : %p", n);
    NSLog(@"Address of n1: %p", n1);
    

    Based on your update, that link I gave you is almost certainly the issue. Someone ran a test and found out that the NSNumbers from 0 to 12 will give you duplicates of those already created (they may in fact be created by the framework even before a user requests them). Others above 12 seemed to give a retain count of 1. Quoting:

    From the little bit of examination I’ve been able to do, it looks as if you will get “shared” versions of integer NSNumbers for values in the range [0-12]. Anything larger than 12 gets you a unique instance even if the values are equal. Why twelve? No clue. I don’t even know if that’s a hard number or circumstantial.

    Try it with 11, 12 and 13 – I think you’ll find 13 is the first to give you a non-shared NSNumber.

    Stop. Just stop. Never look at the retainCount of an object. Ever. It should never have been API and available. You’re asking for pain.

    There’s too much going on for retainCount to be meaningful.

    Retain counts are an implementation detail. They can be kindasorta useful in debugging, sometimes, but in general you should not care about them. All you should care about is that you’re following the memory management rules.

    For an example of why looking at retain counts is unreliable, this is a perfectly legal class that obeys the API contract and will behave correctly in all circumstances:

    @implementation CrazyClass
      - (id)retain {
          for(int i=0; i<100; i++) {
              [super retain];
          }
      }
    
      - (void)release {
          for(int i=0; i<100; i++) {
              [super release];
          }
      }
    @end
    

    …but if you inspected its retain count, you’d think you had an “issue.”

    This precise case doesn’t happen too often in practice, but it illustrates why looking at retain counts is useless for telling if something is wrong. Objects do get retained behind the scenes by code outside of your control. NSNumber, for example, will sometimes cache instances. Objects get autoreleased, which isn’t reflected in the retain count. Lots of things can happen that will confuse the retain count. Some classes might not even keep their retain counts where you can see them.

    If you suspect you have a leak, you should check with the real debugging tools meant for that purpose, not by poking at retain counts. And for code you’re writing, you should primarily be concerned with following the guidelines I linked above.

    You should never rely on the retainCount of an object. You should only use it as a debugging aid, never for normal control flow.

    Why? Because it doesn’t take into account autoreleases. If an object is retained and subequently autoreleased, its retainCount will increment, but as far as you’re concerned, its real retain count hasn’t been changed. The only way to get an object’s real retain count is to also count how many times it’s been added to any of the autorelease pools in the autorelease pool chain, and trying to do so is asking for trouble.

    In this case, the retainCount is 2 because somewhere inside alloc or initWithInt:, the object is being retained and autoreleased. But you shouldn’t need to know or care about that, it’s an implementation detail.

    I think you have something else going on…

        NSNumber* n = [[NSNumber alloc] initWithInt:100]; 
        NSNumber* n1 = n;
        NSLog(@"n = %i",[n retainCount]);
    

    Result is 1