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];
Related
What is the result of the following?
NSString *myStr = [[[NSString alloc] initWithString:#"Hello World."] autorelease];
myStr = [NSString stringWithString:#"Hello Again."];
Does myStr get correctly released or does this crash, since we would call autorelease on myStr which is now set to a string that is already autoreleased?
Your code example works the way you would expect. autorelease can't somehow change what object it refers to after you send the message. The #"Hello World." and #"Hello Again." objects are different objects, even though your example uses the same pointer variable to refer to them.
I'm new to Objective-C and I am having some difficulty with understanding memory management.
So let's say I have a class and an instance variable of type NSString* that isn't tied to a property. Would this situation leak memory?
myString = [[NSString alloc] init];
//more program stuff
myString = [[NSString alloc] init];
Should I have called [myString release] before I set myString equal to a new object? Will this sort of code leak memory? Do I have to release an object like this every time I have the pointer point to a different object?
First, Apple's Memory Management Programming Guide is a great place to look for examples and instructions about memory management.
Now to your question. When you call myString = [[NSString alloc] init]; you are reassigning the pointer myString and as such lose access to the original NSString, thus creating a memory leak.
The general rule of thumb here is that for every alloc you should have a release and these must alternate appropriately. If you do
myString = [[NSString alloc] init];
// ...
myString = [[NSString alloc] init];
// ...
[myString release];
[myString release];
you are releasing the same instance twice which results in overreleasing and an error BAD-ACCESS. The correct thing to do is
myString = [[NSString alloc] init];
// ...
[myString release];
myString = [[NSString alloc] init];
// ...
[myString release];
so that each instance is correctly released.
For future, stick to the simple rule that for every alloc/copy/retain you should pair it with a release.
Yes this will leak.
By allocating and assigning another NSString instance to the same variable myString, you lose reference to the original content of myString and therefore the ability to send it a release message.
Both, the Clang static analyzer and the Leaks instrument should uncover this leak.
Yes, you need to release the first object before you reassign your variable to point to the second object. Otherwise, you lose track of your first object and you leak it because you can't release it. You are responsible for releasing the object because you created it (via alloc) as explained in the Memory Management Rules.
Also, bear in mind that [[NSString alloc] init] is creating an empty and immutable string (NSStrings are immutable meaning that they can not be changed after creation). There is little point in doing this.
I have a comprehension question. This method is given:
- (NSArray*)test {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://stackoverflow.com/"]];
NSString *result = [[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSMacOSRomanStringEncoding];
result = [result stringByAppendingString:#"something"];
NSArray *arr = [NSArray arrayWithObject:result];
//[result release];
return arr;
}
If I uncomment the release the App would crash and say it cannot access a released object.
By not releaseing the result string Instruments would report a leak (NSPlaceholderString).
I can autorelease it on the same line I alloc it, that would solve the problem (which I'm currently doing in my App).
If I understand it correctly stringByAppendingString: should create an autoreleased object so the 'old' result could be deallocated. Then the method arrayWithObject: should copy the object into an array. So my thought was to release the string after it was copied to the array.
Am I missing something or something wrong with my knowledge?
Let's go through your code line by line.
- (NSArray*)test {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://stackoverflow.com/"]];
This creates a data object. You don't own it, but it will stick around for the rest of the method's time. So far, so good.
NSString *result = [[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSMacOSRomanStringEncoding];
This creates a string object that you own. Again, no problem here — we just need to release it later.
result = [result stringByAppendingString:#"something"];
You throw away your reference to the string object that was in result and store a new string object that you do not own. This is a leak because you can no longer release the original string. Also, you're correct in noting that the new string can be treated as an autoreleased object — which means you should not release it.
NSArray *arr = [NSArray arrayWithObject:result];
Contrary to your belief, this does not copy anything. It merely keeps a reference to the new string and retains it.
//[result release];
You should not release result at this point, because the object it contains is not one you own — you got it from stringByAppendingString:, not from a method with new, alloc, retain or copy in its name. Releasing this object that you do not own will almost certainly result in a crash at some point. The old object that you own and should release was lost two lines earlier, and releasing something else in its place won't help.
result = [result stringByAppendingString:#"something"];
This line replaces the first allocated string by a new autoreleased string.
So the first string is leaked and the second one should not be released. This explains why uncommenting the release line crashes.
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.
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.