NSString retain Count - objective-c

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.

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.

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.

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.

Related

Objective-C: What is the difference between creating an object from alloc/init and class method calls?

For example,
NSString *string = [NSString stringWithString:#"a string"];
NSString *string = [[NSString alloc] initWithString:#"a string"];
and while we're talking about strings, is there any difference by setting up a string with:
NSString *string = #"a string";
?
As a final note, this isn't a specific question about NSString. I'm asking on a wider scope of all NSObjects.
There is no difference in ARC, but prior to it there was a difference: alloc/init returns an item with ref count of at least one that you'd need to release when you don't need it, while the class method returns an autoreleased item that you'd need to retain if you would like to keep it. The ARC compiler knows all this, and takes care of retaining/releasing for you based on your ownership specifications.

Basic difference between following NSString assignment calls

// Directly assigning the value.
NSString *str = [objDictionary objectForKey:#"attributeName"];
// Assigning with convenience method
NSString *str = [NSString stringWithFormat:#"%#", [objDictionary objectForKey:#"attributeName"]];
// Assigning after being owner to that object.
NSString *str = [[NSString alloc] initWithString:#"%#", [objDictionary objectForKey:#"attributeName"]];
In what cases, We need to identify which one needed to be used in code. ???
Any Reference links for difference between the same???
Or can someone answer the question in depth???
Thanks for the help.
NSString *str = [objDictionary objectForKey:#"attributeName"];
This is the declaration where you want to user local variable with autorelease memory assigned
i.e. you don't need to worry about memory allocation/deallocation.
NSString *str = [NSString stringWithFormat:#"%#", [objDictionary objectForKey:#"attributeName"]];
This method is useful when you need to combine different types in single string
i.e. integer/float with string
for e.g.
NSString *str = [NSString stringWithFormat:#"%# and %d", [objDictionary objectForKey:#"attributeName"], 5];
This will result in 'your value and 5'
NSString *str = [[NSString alloc] initWithString:#"%#", [objDictionary objectForKey:#"attributeName"]];
This is the assignment where you are allocating memory and you need to have that variable to use some other place so it will be there until and unless you release the memory of that variable.
Make sure when you allocate memory you release memory yourself as you are the responsible one.
For further detailed study I recommend you to visit documentation for NSString which will give you idea about available class/instance methods and how to use.
Assuming your dictionary contains a string, under ARC, these are all identical. With manual reference counting, the first two are autoreleased and the last one is retained.
For a reference guide, you can't do much better than the NSString class reference.

init, alloc and retain and "the initial value is never read"

Ive have used the static analyser to look through my code and have arrived at the following question.
NSString *string = [[NSString alloc] init];
string = [object name];
This give me a memory error saying that the initial value is never read.
I replaced it with the following
NSString *string = [[object name]retain];
Is this better/correct coding?
Cheers
This code:
1: NSString *string = [[NSString alloc] init];
2: string = [object name];
is incorrect because in line 1: you allocate new memory and store reference to it in variable string. In line 2: you store in variable string reference to another memory location.
As a result, you didn't read memory value that was allocated at line 1: and even didn't release it. So moreover you have memory leak there.
If you want to save reference to some place in memory you don't need alloc+init. You should use alloc+init when you want to allocate some space in memory where you will write data or read from.
Your variable string is actually a pointer to an NSString object. The first line of your code created a new empty string and assigned a pointer to it to string. The second line of code then immediately overwrites that pointer with a pointer to a completely different string. You have never read the original value, and there is no way to access the allocated NSString, thus it has leaked.
The second option is correct., provided you release/autorelease it somewhere later.
I have seen someone else do this exact thing. NSString *string = [[NSString alloc] init]; creates a new object and assigns it to string. string = [object name]; Assigns the name of object to string. It is similar to saying int a = 0; a = 4, 0 has no effect on the 4. The problem with your code is that [[NSString alloc] init] creates a new object with a retain count of 1, because you do not release it it leaks. [object name] returns an autoreleased object which will disappear at the end of the runloop.
In short, use NSString *string = [[object name] retain];

Assign to NSString after alloc/init

This doesn't seem to work:
NSString *string = [[NSString alloc] init];
string = #"%#M", anotherstring;
I expect this to make "string" equal to "5M" if "anotherstring" is "5".
Is this not the right syntax? Now, I could use initWithFormat and it would work, but how can you separate it into two different lines and also work?
There are two mistakes in your code. Firstly, NSStrings are immutable, and once you allocate and initialize them, they're set, and there's no way to change them. For that, you'd have to look into NSMutableString.
Secondly, the syntax of your code makes no sense. #"%#M", anotherString is not a valid Objective-C method call. You are indeed looking for -initWithFormat: to perform the operation you want. The code should look like this:
NSString *string = [[NSString alloc] initWithFormat:#"%#M", anotherString];
Read more about NSString and how to use it in the NSString Programming Reference document, and the String Programming Guide to get a sense of how to work with strings in Cocoa and Objective-C.
This line:
string = #"%#M", anotherstring;
is syntactically correct, but it doesn't do what you want it to do. This is how you format a string:
NSString *string = [[NSString alloc] initWithFormat:#"%#M", anotherstring];
There's no point in separating it into two lines. This:
NSString *string = [[NSString alloc] init];
string = [[NSString alloc] initWithFormat:#"%#M", anotherstring];
will create an extra NSString object, and also cause a memory leak.
How about
NSString* string;
string = [[NSString alloc] initWithFormat:#"%#M", anotherString];
Keep in mind that the = operator is assignment. Any time you use it, any value was stored in your variable is overwritten with the new one. So even if your original code was syntactically correct it still has faulty semantics that would, in this case, cause a memory leak.
just make it into a property and you dont need to worry about releasing and retaining the "string" (that is if you autocreate it by using synthesize). and dont forget to autorelease the object ur assigning to the property:
self.string = [[[NSString alloc] init] autorelease]

When not to alloc and init an NSString

Whenever I need to create a new NSString variable I always alloc and init it. It seems that there are times when you don't want to do this. How do you know when to alloc and init an NSString and when not to?
Whenever I need to create a new NSString variable I always alloc and init it.
No, that doesn't make sense.
The variable exists from the moment the program encounters the point where you declare it:
NSString *myString;
This variable is not an NSString. It is storage for a pointer to an NSString. That's what the * indicates: That this variable holds a pointer.
The NSString object exists only from the moment you create one:
[[NSString alloc] init];
and the pointer to that object is only in the variable from the moment you assign it there:
myString = [[NSString alloc] init];
//Or, initializing the variable in its declaration:
NSString *myString = [[NSString alloc] init];
Thus, if you're going to get a string object from somewhere else (e.g., substringWithRange:), you can skip creating a new, empty one, because you're just going to replace the pointer to the empty string with the pointer to the other one.
Sometimes you do want to create an empty string; for example, if you're going to obtain a bunch of strings one at a time (e.g., from an NSScanner) and want to concatenate some or all of them into one big string, you can create an empty mutable string (using alloc and init) and send it appendString: messages to do the concatenations.
You also need to release any object you create by alloc. This is one of the rules in the Memory Management Programming Guide.
If you want to initialise it to a known value, there is little point in using alloc, you can just use a string literal:
NSString* myStr = #"Some value";
If you want to initialise it with a format or whatever, but don't need it to stick around beyond the current autorelease pool lifetime, it's a bit neater to use the class convenience methods:
NSString* myTempStr = [NSString stringWithFormat:#"%d", myIntVar];
If you need its lifetime to go beyond that, either alloc/init or else add a retain to the previous call. I tend to slightly prefer the latter, but the two are pretty much equivalent. Either way you will need a balancing release later.
Note that, since NSString is not mutable, this sort of thing is not only unnecessary but actively wrong:
// don't do this!
NSString* myStr = [[NSString alloc] initWithString:#""];
myStr = someOtherStr;
since it leaks the initial placeholder value.
It seems that there are times when you don't want to do this.
I can't think of any time when I would want to alloc/init a NSString. Since NSStringgs are immutable, you pretty much always create new strings by one of:
convenience class method e.g.
NSString* foo = [NSString stringWithFormat:...];
literal
NSString* foo = #"literal";
NSString instance method
NSString* foo = [bar uppercaseString];
copy from mutable string
NSString* foo = [mutableBar copy]; // foo needs to be released or autoreleased in this case
I'm guessing that you are referring to using StringWithString or similar instead of initWithString? StringWithString alloc and inits for you under the hood and then returns an autoreleased string.
If you don't need to do any string manipulation other than to have the string, you can use NSString *str = #"string";
In general with iOS, the tighter you manage your memory the better. This means that if you don't need to return a string from a method, you should alloc init and then release it.
If you need to return a string, of course you'll need to return an autoreleased string. I don't think its any more complicated than that.