Why does NSNumber wrong count a retaincount? - objective-c

Here is retaincount code.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
#autoreleasepool {
NSNumber *number = [[NSNumber alloc]initWithInt:10];
NSMutableArray *array = [[NSMutableArray alloc]initWithCapacity:0];
NSLog(#"retain count : %d",[number retainCount]);
[array addObject:number];
NSLog(#"retain count : %d",[number retainCount]);
[number release];
NSLog(#"retain count : %d",[number retainCount]);
[number release];
NSLog(#"retain count : %d",[number retainCount]);
[number release];
NSLog(#"retain count : %d",[number retainCount]);
}
return 0;
}
My expected answer is
retain count : 1
retain count : 2
retain count : 1
retain count : 0
and then error
but actually running result is as following.
[Switching to process 6363 thread 0x0]
2011-12-01 19:39:53.843 nsnumber[6363:707] retain count : -1
2011-12-01 19:39:53.846 nsnumber[6363:707] retain count : -1
2011-12-01 19:39:53.847 nsnumber[6363:707] retain count : -1
2011-12-01 19:39:53.847 nsnumber[6363:707] retain count : -1
2011-12-01 19:39:53.848 nsnumber[6363:707] retain count : -1
I can't understand this result.
Why is this the result will come?

Don't trust the value of retain count. Especially as you are using ARC! Follow the rules. That's all.

NSNumber returns singleton instances for certain numbers (I believe integers 1 to 12, or something).
You shouldn't ever rely on the value of retainCount. Any number of things could be happening throughout your code or framework code that can change the retain count.

About retainCount
This method is typically of no value in debugging memory management
issues. Because any number of framework objects may have retained an
object in order to hold references to it, while at the same time
autorelease pools may be holding any number of deferred releases on an
object, it is very unlikely that you can get useful information from
this method.
See also
http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/retainCount
When to use -retainCount?

The return type of retainCount is NSUInteger; that's an unsigned integer. The string format specifier %d is for a signed integer.
Cocoa uses NSUIntegerMax to represent the retain counts of immortal objects -- objects which will never be released. For performance reasons, it caches and reuses NSNumber objects representing small integers -- this NSNumber that you've created is apparently one of those, and is immortal.
When you interpret the maximum unsigned integer value as if it were signed (under two's complement arithmetic), it appears to be -1.
To see the "true" value, you should use the specifier %lu, as indicated by the chart I linked to above.
However, you generally shouldn't rely on retainCount to give you any useful information. This is documented:
Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
as beryllium already noted.

Related

How to find the Retain count?

Please explain me the below code of lines, I am just confused..,
Nsstring *a;
Nsstring *b;
a = [b retain];
what is the retain count of a & b.
a = [b copy];
what is the retain count of a & b.
Thanks in advance.
Technically the retain count in the situation you posted is indeterminate, since you never initialize your variables. Calling retain on an uninitialized pointer will probably crash.
Second, the retain count in your situation depends on how you init your variables.
NSString *a;
NSString *b = #"test";
a = [b retain];
/* Both variables reference the same object which has been retained.
Retain count +1
*/
NSString *a;
NSString *b = #"test 2";
a = [b copy];
/* `a` has a retain count +1 (a variable returned from a `copy`
method has a retain count +1). `b` retain count does not change
(you haven't called `retain` on `b`, so it's count remains the
same.
*/
If you haven't done so yet, you should read Apple's memory management guidelines. Also, unless you have a very good reason not to, you should be using ARC, which frees you from most of the headaches from manually managing memory.
In the comments on the other answer, you ask how to determine the retain count for an object. You always keep track of it yourself. Other objects may retain and release your string, but you don't care. If you create and object using alloc, call retain on an object or copy an object, you are responsible for releasing or autoreleasing that object when you are finished with it. Otherwise it isn't your responsibility. The absolute retain count of an object never matters.
NSString doesn't have a retain count that will make sense. But if you're using as a general example, the way to find the retain count for objects that have a normal retain count is:
[a retainCount]

Reference count is still 1 after [obj release], when it should be deallocated

When I create an object and check its retain count, I get 1 as expected. When I release the object and then check the retain count again, it is still 1. Shouldn't the object be deallocated, and the retain count 0?
NSMutableString *str=[[NSMutableString alloc] initWithString:#"hello"];
NSLog(#"reference count is %i",[str retainCount]);
[str release];
NSLog(#"reference count is %i",[str retainCount]);
I do see 0 for the retain count if I set str to nil first. Why is that?
Don't use retainCount, it doesn't do what you expect in most cases.
Your second NSLog is accessing deallocated memory as an object. In this particular case, that deallocated memory still contains enough of the old data from the NSString that was just freed for the program to not crash when the retainCount method is called on it. Had you run this with NSZombieEnabled you would have gotten an error message about sending a message to a deallocated instance.
The reason it returns 0 when called for nil is that methods returning integers will always return 0 when called on a nil object.
Do not depend on retainCount. And do not care about this. Lots of things may happen under the hood. You only need to ensure that you have released all the things that you owned. If you are trying to be sure that you are not leaking any memory, then use Instrument, not retainCount in NSLog.

Retain count in objective C return -1

I'm new to objective C, I have a NSMutableArray with 3 objects in it, then I try to print the retainCount of the array. Why the final retainCount return -1? Thanks
NSLog(#"myArray has retain count of %d", [myArray retainCount]);
[myArray release];
NSLog(#"myArray has retain count of %d", [myArray retainCount]);
Result from console:
2010-10-17 11:58:06.407 TestRetainCount [527:a0f] myArray has retain count of 1
2010-10-17 11:58:06.407 TestRetainCount [527:a0f] myArray has retain count of -1
After an object has been deallocated (which may happen after a release), you can no longer rely on its data being intact. You're trying to trust the retain count after it has become invalid.
On a general note, don't use the retain count. Ever. Use the rules in the memory management programming guide, and you'll always get the reference counting correct.
Graham Lee answered the question specific to your example.
not specific to your example, but to your question (subject):
UINT_MAX is often used to denote an object which uses no reference counting (e.g., is never deallocated, such as a singleton), or a custom reference counting implementation.
Can't rely on an accurate retainCount because of the timing autoreleased objects. That said, count your alloc/init, new, retains, etc... and match with corresponding release.

copy an NSMutableString instance returns retainCount of -1

Can someone explain why the last line prints out -1? It happens when copy is called on a NSMutableString, I expect the returnCount of strFour to be 1, since an immutable copy should be returned.
NSMutableString *str =[NSMutableString stringWithString:#"hi"];
NSLog(#"new instantiated variable has a retain cout:");
NSLog(#"%d",[str retainCount]); //1, str is a pointer, its value is a memory address
NSMutableString *strFour =[str copy]; //receiver str is mutable, copy returns an immutable
NSLog(#"%d",[strFour retainCount]); ////strFour s retain count should be 1, but it had a retain count of -1
Thanks a lot.
Never bother looking at the retain count of an object. It is always meaningless to do so. The retain count is likely affected by optimisations “under the hood”. These optimisations rely on the fact that your code follows the Cocoa Memory Management Guidelines. Just worry about sticking to those guidelines and don't bother looking directly at the retain count.
One reason why it could be (-1) because the string “hi” may be cached somewhere and your copy is referring to the cached string. Keep in mind that the retain count is actually an unsigned integer. The documentation dor -retainCount says that for objects that never get released, the retain count should be UINT_MAX (which when printed as a signed decimal will come out as “-1”).

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:
NSNumber *n = [[NSNumber alloc] initWithInt:100];
// n has a retainCount of 1
NSNumber *n2 = [[NSNumber alloc] initWithInt:11];
// n has a retainCount of 2
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.
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.
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
There is however a fly in this ointment. I've seen crashes due to retain count overflows from NSNumber instances containing small integers. In large systems that run for a very long time you can exceed the max int and get an Internal Consistancy error.
NSInternalInconsistencyException: NSIncrementExtraRefCount() asked to increment too far for <NSIntNumber: 0x56531f7969f0> - 0