7

Just couple of days i was working on a project and i have to see what is retain count of a string.

But it always return me "2147483647", Why it is so?

Check out this code to check it yourself.

NSString *str = [[NSString alloc] initWithString:@"Hello World"];
NSLog(@"String Retain Count: %i", [str retainCount]); 

So my question is why it is not returning 1 like other objects return, why i am getting "2147483647"

Thanks in advance.

itsaboutcode
  • 24,525
  • 45
  • 110
  • 156
  • Why is this a community wiki? – Dave DeLong Sep 07 '09 at 18:06
  • Well sorry if i click somewhere where i should not, new to this website so really don't know what it mean, sorry. – itsaboutcode Sep 07 '09 at 18:15
  • Don't worry. It's fine to make it a community wiki. – Chuck Sep 07 '09 at 19:21
  • However, it's not OK for you to ignore advice from experienced Cocoa programmers and just be like, "Whatever! I'm going to use NSMutableStrings instead of learning to use Cocoa properly!" – Chuck Sep 07 '09 at 19:23
  • Well i am not ignoring their advice or something, but right now i am unable to grasp the concept, for just not to stay in confusion, its best for me to use NSMutableString, because i hate confusion loz. – itsaboutcode Sep 07 '09 at 19:35
  • What's confusing about it? If you follow the memory management rules, you'll never go wrong: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html Direct quote: "Typically there should be no reason to explicitly ask an object what its retain count is (see retainCount). The result is often misleading, as you may be unaware of what framework objects have retained an object in which you are interested. In debugging memory management issues, you should be concerned only with ensuring that your code adheres to the ownership rules." – Dave DeLong Sep 07 '09 at 19:53
  • Duplicate of http://stackoverflow.com/questions/403112/objective-c-nsstring-property-retain-count-oddity And there's a good answer there too. – marcc Sep 07 '09 at 17:38

3 Answers3

27

The compiler is smarter than you.

It sees @"Hello world" and thinks "Aha! A constant string!"

It then sees [[NSString alloc] initWithString:@"Hello world!"] and thinks "Aha! An immutable object created with a constant string!"

It then collapses both of them down into a single NSConstantString, which has a retainCount of UINT_MAX, so that it can never be released.

James Raitsev
  • 92,517
  • 154
  • 335
  • 470
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • OK can you tell me the way through which i will get the retain count of 1, in case of NSString? – itsaboutcode Sep 07 '09 at 17:59
  • 2
    @itsaboutcode I would recommend not thinking about this in terms of retainCounts, but instead think about "I allocated this string, so I must release it", and let the retainCounts sort themselves out. In the few years I've been writing in Objective-C, I can't think of a single instance when I've needed to bother with the retainCount. If you follow the memory management rules, you'll be fine. – Dave DeLong Sep 07 '09 at 18:05
  • @ Dave DeLong That is how i have been thinking, if have created an object with NSString *str = [[NSString alloc] initWithString:@"Hello World"]; Then i should release it, right? But if i have to release it i should know what is its retain count? Otherwise i will be sending messages to object which is not there and result will be that my program will crash! – itsaboutcode Sep 07 '09 at 18:10
  • But i have found a strange behavior here. When i do the same thing with NSMutableString, it return me a retian count of 1. NSMutableString *str = [[NSMutableString alloc] initWithString:@"Hello World"]; NSLog(@"String Retain Count: %i", [str retainCount]); Check this out. – itsaboutcode Sep 07 '09 at 18:12
  • Dave, you don't need to worry about what the retain count *is*, just that you have the correct number of init/releases in your code. If you init something, you release it, and that's all good. The specialisation of UINT_MAX in this case means that even if you do release it, it will still be UINT_MAX afterwards. – AlBlue Sep 07 '09 at 18:14
  • 1
    @itsaboutcode if you alloc it, you release it. End of story. If your code crashes on the release because you've over-released the object, then you've done wrong. The reason that the NSMutableString returns a retainCount of 1 is *precisely* because it is mutable. It can be changed, which means the compiler cannot optimize it into a constant string. – Dave DeLong Sep 07 '09 at 18:16
  • @AlBlue - I know (see my first comment). I put it in there to explain why the retainCount he was getting was so high. – Dave DeLong Sep 07 '09 at 18:17
  • @Dave From your answer it seems to me that every immutable object will get a retain count of "UINT_MAX", but i dont think so its the case? – itsaboutcode Sep 07 '09 at 18:23
  • @Dave So in case of NSString, i should be releasing it? – itsaboutcode Sep 07 '09 at 18:26
  • @itsaboutcode it's possible. it really depends on the compiler. But YES you should release it. You called +alloc, which means you should call -release. – Dave DeLong Sep 07 '09 at 18:43
  • @Dave Thats the problem, though i am releasing it but every time i release it it's retain count remain "2147483647", so i have decided not to use NSString ever again and i will only use NSMutableString instead so that i have no problem in debugging my app. Thanks everyone. – itsaboutcode Sep 07 '09 at 18:50
  • 1
    @itsaboutcode IGNORE RETAINCOUNTS. NSString is there for a reason: use it when you don't need a mutable string. If you alloc an object, release it. It's really not that difficult... – Dave DeLong Sep 07 '09 at 19:12
  • 1
    Retain counts are for the computer, not for you. You should only be concerned with what you own, and relinquishing your ownership when you are done. The coalescing into a single constant string is memory savings for you. if (!horse.isAlive) { [self beat:horse]; } – Wevah Sep 07 '09 at 22:15
4
NSString *str = [[NSString alloc] initXXX 

usually would allocate some RAM and return you a pointer. This RAM would then be subject to releases and reatins. However, when you do:

NSString *str = [[NSString alloc] initWithString:@"Hello World"];

the string returned is @"Hello World", which is already allocated because it was a string literal. Since it is a string literal, there is no way to release it, and thus the system has to mark it as unreleasable. The way it does that is to set its retain count to the max integer value.

NString  *str = [[NSString alloc] initWithFormat:@"Hello World. Today is @%", todayDate];

This string will have a retainCount of 1. Although there is a string constant in there, it is appended to by another string. Since you can't modify that constant string, a copy of the "Hello World. " string is made, and the content of the todayDate string is added to that. That memory now is given ownership to the caller, with a retainCount of 1.

mahboudz
  • 39,196
  • 16
  • 97
  • 124
2

The string is being optimized at compile-time to a statically allocated instance of NSString in order to save on some variable overhead and the like. You're seeing such a high retain count because static strings have a retain count of the maximum integer on whatever platform you're developing on.

Tim
  • 59,527
  • 19
  • 156
  • 165