Memory management issue with NSString - ios

I have NSMutableArray* cityData that I fill with custom LocationDetail objects. cityData is created in viewDidLoad and released in dealloc.
Somewhere in the code, based on user actions, I populate LocationDetail and add it to cityData array:
LocationDetail* d = [[LocationDetail alloc] init];
d.city = [NSString stringWithFormat:#"%S", (char*)sqlite3_column_text16(statement, 1)];
d.tz = [NSString stringWithFormat:#"%S", (char*)sqlite3_column_text16(statement, 3)];
d.country = [NSString stringWithFormat:#"%S", (char*)sqlite3_column_text16(statement, 2)];
d._id = [NSString stringWithFormat:#"%S", (char*)sqlite3_column_text16(statement, 0)];
[cityData addObject:d];
[d release];
When I am finished with the view controller and remove it, Leaks utility says I have a leak in the code above in NSCFString in all 4 lines with [NSString stringWithFormat] above.
I tried removing the sqlite3 stuff and simplified the call to something like
d._id = [NSString stringWithFormat:#"%s", "a string"]
with the same result. However, if I replace the NSString stringWithFormat like this:
d._id = #"a string";
the leak goes away. I wonder why there is a leak if I use the stringWithFormat, but not if I use #"something". Is there anything obvious that I'm doing wrong?
Thanks!

Properties are not automatically released for you, you need to do that yourself in
- (void)dealloc
See The Objective-C Programming Language: Declared Properties for an example.
Edit:
It seems that the example was moved into the Advanced Memory Management Programming Guide.

Related

Objective C, what [NSString initWithFormat] exactly does?

I just would like to know the difference between the line 1 and 2 bellow:
_subtitle = #"Test"; //Line 1
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2
If I asked that question, it is because I got a problem by using MKAnnotation. In the method bellow, I try to update the subtitle delegate property of MKAnnotation (which is nonatomic, copy and readonly). But it's look like that I got a zombie when using the line 2 and nothing when using the line 1. So my question is why?
- (void) initCoordinateWithAddress:(NSString*)address;
{
self.address = address;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString: address completionHandler:^(NSArray *placemarks,NSError *error)
{
CLPlacemark *place = [placemarks objectAtIndex:0];
_coordinate = place.location.coordinate;
_title = self.address;
_subtitle = #"Test"; //Line 1: don't crash
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2: crash
//_subtitle = [[NSString stringWithFormat: #"[%.2f,%.2f]", self.coordinate.latitude, self.coordinate.longitude] copy];
_isInit = YES;
[self.customDelegate didCalculateCoordinate: place.location.coordinate forAnnotation: self];
}];
}
I actually already fixed my problem by using the method copy, but I still not understand what is the difference between the line 1 and 2, if anyone can help me to understand what the difference is, I will appreciate.
Edit:
1- I am not using ARC
2- _subtitle comes form #synthesize subtitle = _subtitle; And subtitle is a part of the MKAnnotation protocol, with the property nonatomic, readonly and copy
Regards,
Cyril
If you are not using ARC, the answer is straightforward and is what Anoop Vaida wrote. However, I think some further explanation is needed.
This line
_subtitle = #"Test";
Creates a reference to a string literal. If you take a peak at its retain count in the current implementation of foundation, you'll find it is a very large number (NSIntegerMax I think). If the code for -release and -retain comes across this value for the retain count, they do not decrement or increment it. Thus string literals have infinite life times.
This line:
_subtitle = [NSString stringWithFormat: #"Test"];
creates a string you do not own. Unless you take steps to claim ownership, it could disappear at any time, most likely when the autorelease pool is drained. Your options are create a string you do own
_subtitle = [[NSString alloc] initWithFormat: #"Test"];
or to retain it.
_subtitle = [NSString stringWithFormat: #"Test"];
[_subtitle retain]; // Can be combined with the previous line if you like.
or to copy it
_subtitle = [[NSString stringWithFormat: #"Test"] copy];
Note that, in all cases, you need to release the previous value of _subtitle before you overwrite it, or you will get a leak e.g.
[_subtitle release];
_subtitle = [[NSString alloc] initWithFormat: #"Test"];
This is why it is better to have a property. Just because the MKAnnotation subtitle property is read only, does not mean you can't override it with your own read/write property. e.g.
#interface MyAnnotation : NSObject <MKAnnotation>
// other stuff
#property (readwrite, copy, nonatomic) NSString* subtitle;
#end
If you then synthesize it, you'll get all the correct memory management code and you can just do
[self setSubtitle: [NSString stringWithFormat: #"test"]];
or, if you must use dot notation
self.subtitle = [NSString stringWithFormat: #"test"];
I just would like to know the difference between the line 1 and 2
bellow:
_subtitle = #"Test"; //Line 1
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2
If you ask just the above these both are same.
While checking your code, the difference is quite visible.
You are creating a new autoreleased subtitle which is getting released once the block is over.
I don't think your solution is to understand how the string initializes work, but more on how blocks deal with variables.
When I think about it I think you may want to try an access _subtitle by it's property and not it's ivar.
self.subtitle
This should increment the retain count and keep everything functioning fine.
If you look up the documentation for initWithFormat: it links you to Formatting String Objects with many examples.
This basically allows (s)printf-style format strings, like so:
NSString *string1 = [[NSString alloc] initWithFormat:#"A string: %#, a float: %1.2f",
#"string", 31415.9265];
// string1 is "A string: string, a float: 31415.93"
The key is to specify arguments by adding a , after the string argument.
The '[NSString stringWithFormat:]' allows you to add a variable into the string, for example:
int myVar = 3;
NSString *myString = [NSString stringWithFormat:#"This number is %i", myVar];
The resulting string would be (if you were to NSLog it, for example): "This number is 3"
However you cannot do it like this:
NSString *myString = #"This number is %i", myVar;
Which would present you with an error.

multiple assignments of objects to variable under ARC

There's a point of memory management I'm not 100% clear on, suppose there is the following code:
{
NSString *string = [[NSString alloc] init];
string = [[NSString alloc] init];
}
Does this cause a memory leak of the first allocation? If not why not?
Under ARC, this does not leak memory. This is because any time a strong object pointer is changed, the compiler automatically sends a release to the old object. Local variables, like NSString *string, are strong by default.
So your code above gets compiled to something more like this:
{
NSString *string = [[NSString alloc] init];
// Oh, we're changing what `string` points to. Gotta release the old value.
[string release];
string = [[NSString alloc] init];
}
Conceptually, BJ is correct, but the generated code is slightly different. It goes something like this:
NSString *string = [[NSString alloc] init];
// Oh, we're changing what `string` points to. Gotta release the old value.
NSString *tmpString = string;
string = [[NSString alloc] init];
[tmpString release];
[string release]; // string goes out of scope at this point in your code
This order of operation is usually not that critical (and if you care too much about it, you are probably coding incorrectly). But understanding it explains why the objects are destroyed exactly when they are.
No it does not cause a leak. ARC will release the first string before it sets the second string. This is the truly amazing power of ARC!

Why is autorelease object still alive?

I've created autorelease pool. localString has added to this pool. I released the pool. localString and string must be deallocated. But in reality they are still alive. You can see my log:
Why is the string object still alive? I don't know.
and code:
-(NSString*) happyString
{
NSString *localString = [[[NSString alloc] initWithString:#"I don't know."] autorelease];
return localString;
}
-(IBAction) onButton:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *string = [self happyString];
[pool release];
NSLog(#"Why is the string object still alive? %#", string);
}
Strings (NSString instances and statically allocated strings with #"") are immutable in Cocoa, so when you try to create a new NSString from a statically allocated one, the NSString class can make an optimisation: a new NSString instance is not created (the object created when you called -alloc is immediately released), and the reference to your statically allocated string is returned. That is, the line:
NSString *localString = [[[NSString alloc] initWithString:#"I don't know."] autorelease];
Is actually equivalent to:
NSString *localString = #"I don't know.";
(If you check the memory addresses of those two objects, you can see that they are the same.)
As this type of string cannot be released, it does not disappear when you expect it to.
If you were to create your string in a way that cannot be optimised, for example:
NSString *localString = [[[NSString alloc] initWithFormat:#"%#", #"I don't know."] autorelease];
Then your code will behave as you expect, and your application will (hopefully) crash at your NSLog line.
If you have tried any classes (any custom classes) other than NSString , then it would not be alive..

How to release a string created inside a method?

I have declared a local string inside the method. I am releasing the string inside the same method. I found my code crashing if release that object. If I don't release the string, code runs successfully.
I have called that method in viewdidappear so that method is called while pushing and poping. Nothing gets printed in the console. Here is my code
-(void)appendString{
NSString *locStr = [[NSString alloc] initWithString:#""];
for (int i=0;i<[result count]; i++)
{
locStr=[locStr stringByAppendingFormat:#"%#",[result objectAtIndex:i]];
}
[str setString:locStr];
[locStr release];
}
I am calling the "appendString" method from "viewDidAppear"."str" is a NSMutable string declared in .h class.How should I release the "locStr".
What went wrong in my code? This isn't the normal way to release it?
Try this:
-(void)appendString{
//stringWithString returns an autorelease object
//so you don't need to worry about its memory management
NSString *locStr = [NSString stringWithString:#""];
for (int i=0;i<[result count]; i++)
{
//if your locstr is created by initWithString instead,
//the following line is going to cause memory leak
locStr=[locStr stringByAppendingFormat:#"%#",[result objectAtIndex:i]];
}
[str setString:locStr];
//[locStr release];
}
And make sure that the string property in your str instance is set to retain
You may want to use NSMutableString and not create multiple string objects that may or may not release at some time in the distant future.
-(void)appendString
{
NSMutableString *locStr = [[NSMutableString alloc] initWithString:#""];
for (int i=0;i<[result count]; i++)
{
[locStr appendFormat:#"%#",[result objectAtIndex:i]];
}
[str setString:locStr];
[locStr release];
}
see
In your code, calling [locStr release] is sent to the NSString instance returned from [locStr stringByAppendingFormat:#"%#",[result objectAtIndex:i]] That code actually returns a new String instance, so your variable locStr is now pointing to that new NSString instance and your reference to the original one is lost.
So it is NOT the instance of the NSString you created with [[NSString alloc] initWithString:#""]
The NSString returned from stringByAppendingFormat is autoreleased and your [locStr release] would over-release it. As the other answers indicate you could just use a NSMutableString to avoid lots of NSString instances to be created in your loop and actually releasing the original created instance.
No need to alloc/init locStr. This should do the trick:
-(void)appendString{
NSString *locStr = #"";
for (int i=0;i<[result count]; i++) {
locStr=[locStr stringByAppendingFormat:#"%#",[result objectAtIndex:i]];
}
[str setString:locStr];
}
Don't release, use autorelease. This is the way if you need to return something. When there is an autorelease pool (which is in most cases) it is released automatically. That's what methods like stringByAppendingFormat do also.
Or wait, when you di something like this, it is important, that you retain the Object in the setter Method. It is better then to use a property like
{
NSString* thestring;
}
#property (nonatomic, retain) NSString* thestring;
and a
#synthesize thestring;
in the .m file.
use this
locStr=[[locStr stringByAppendingFormat:#"%#",[result objectAtIndex:i]] retain];
then you can release this same as you are doing.
what happens here you get an autorelease object of string by stringByAppendingFormat method.
so you need to convert it into a retain copy.

Using substringFromIndex on NSMutableString

Why is substringFromIndex not working for my NSMutableString ?
Here code similar to what I have :
NSMutableString *myString = [[NSMutableString alloc] initWithString:#"This is my String"];
[myString substringFromIndex:5];
NSLog(#"myString = %#", myString); //will output This is my String
If I use substringFromIndex on NSString it will work, for example like so :
NSString *tempStr = [[NSString alloc] init];
tempStr = [myString substringFromIndex:5];
NSLog(#"tempStr = %#", tempStr); //will output is my String
Why does it not work in the first example, and I have one more question, if I do it using the second method, and then I set:
[myString setString:tempStr];
[tempStr release];
This will result in a crash, I thought, since I used setString on NSMutableString, that I do not need the NSString and I release it, but apparently that is not the case, however if I use autorelease it will be OK
That method never alters the string you call it on. It returns a new string in both cases. So assign it to a new string variable and your good.
It's crashing because you over releasing one object and and leaking another. You alloc the first string, then make a new autoreleased string from substringFromIndex:, then release it. You dont need to try this hard.
Simply assign the output of the substring method to a variable, and let it be autoreleased for you. No alloc, no release.
A full proper example might look like this:
NSMutableString *myString = [[NSMutableString alloc] initWithString:#"This is my String"];
NSString *tmpString = [myString substringFromIndex:5];
NSLog(#"tempStr = %#", tempString);
[myString setString:tempStr];
// later do [myString release]
or even simpler:
NSString *myString = #"This is my String";
myString = [myString substringFromIndex:5];
You create an NSMutableString specifically so you CAN modify it.
But no one knows any way to do this:
[myMutableString substringFromIndex:5];
And if you are going to do this instead:
myMutableString = [myMutableString substringFromIndex:5];
why even use a mutable in the first place.
MutableStrings are great for ADDING (appending) to them.
Not sure why we can't also shorten (substring) them. (Without making a new copy.)
[myString substringFromIndex:5] returns a new NSString that starts from the specified index. It does not modify myString.
try this code instead:
NSLog(#"myString = %#", [myString substringFromIndex:5]);

Resources