views:

1752

answers:

5
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 set to 2 is not related to the assignment of second line of the code.

the retainCount depends on the initial number.

1.

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

NSLog(@"Count of n : %i",[n retainCount]); //retainCount is 1

2.

NSNumber* n = [[NSNumber alloc] initWithInt:11];

NSLog(@"Count of n : %i",[n retainCount]); //retainCount is 2

+2  A: 

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

dizy
it's very strange, the result in my xcode is 2. the following code is copied from my xcode:NSNumber* n = [[NSNumber alloc] initWithInt:11]; NSNumber* n1 = n; NSLog(@"%i",[n retainCount]);
Jiang
+3  A: 

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.

Jim Puls
Would you like to elaborate please?
dizy
Agreed. Every `alloc` needs a `release`. That's all you should worry about. Concerning yourself with the `retainCount` means concerning yourself with what might be going on inside Apple's frameworks. You can trust that their code will be right (even if it isn't, it's not your job to fix).
Matt Ball
+6  A: 

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.

paxdiablo
you are right. i tried 13, the retainCount became 1.
Jiang
+4  A: 

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.

Chuck
+3  A: 

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.

Adam Rosenfield
No, you shouldn't use it as a debugging aid, either. It's just as useless for that.
Jim Puls