Why does this line leak memory? - iphone

[row setObject:[NSString stringWithCString:value encoding:NSUTF8StringEncoding] forKey:columnName];
where row is a NSMutableDictionary..is there a different way to inject this string into my dictionary?

Profiling tools says that because the string is "autoreleased", so you could optimize it by
putting a NSAutoreleasePool around it
alloc/init the str then release it
or just ignore the optimization message.
This is one way:
NSString *str = [[NSString alloc] initWithCString:value encoding:NSUTF8StringEncoding];
[row setObject:str forKey:columnName];
[str release];

I have had this problem before, because the NSMutableDictionary owns the object it won't be released until the Dictionary is released.
I would suggest that somewhere in your code an object is being dealloc'd without properly releasing the variables it owns, likely the NSMutableDictionary *row.

Related

Why does this Code cause the EXC_BAD_ACCESS error?

Here's a piece of code I wrote for cleaning A string of unwanted chars and double spacing.
However, I seem to have misunderstood memory management somewhere and it keeps causing the EXC_BAD_ACCESS error. The Code works fine functionally when the release statements are removed but that would cause memory leaks.
-(NSString*) cleaningString:(NSString*) input {
NSCharacterSet* wantedCharacters=[[NSCharacterSet alloc] init];
wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
NSString* cleanStringOutput=[[NSString alloc] initWithString:#""];
NSString* currentLetter =[[NSString alloc] initWithString:#" "];
NSRange unwantedCharacters=[currentLetter rangeOfCharacterFromSet:wantedCharacters];
for (int i=0; i<input.length; i++) {
currentLetter=[NSString stringWithFormat:#"%c",[input characterAtIndex:i]];
unwantedCharacters=[currentLetter rangeOfCharacterFromSet:wantedCharacters];
doubleSpace=YES;
if (i<input.length-1) {
if (([currentLetter isEqualToString:#" "])&&([[NSString stringWithFormat:#"%c",[input characterAtIndex:i+1]] isEqualToString:#" "])) {
doubleSpace=NO;}
}
else {
if ([currentLetter isEqualToString:#" "]) {
doubleSpace=NO;
}
}
if ((unwantedCharacters.location!=NSNotFound)&&(doubleSpace))
{
cleanStringOutput=[NSString stringWithFormat:#"%#%#", cleanStringOutput, currentLetter];
}
}
if (cleanStringOutput.length>0){
if ([[NSString stringWithFormat:#"%c",[cleanStringOutput characterAtIndex:0]] isEqualToString:#" "]){
cleanStringOutput=[cleanStringOutput substringFromIndex:1];
}
}
[currentLetter release];
[wantedCharacters release];
[cleanStringOutput autorelease];
return cleanStringOutput;
}
Please forgive me if I just asked something painfully obvious.
P.S. And another question. Is it necessary to release the NSRange?
Right here
NSCharacterSet* wantedCharacters=[[NSCharacterSet alloc] init];
wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
You discard your original object and replace it with an autoreleased one
Which will crash when you call
[wantedCharacters release];
Do this
NSCharacterSet* wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
and forget the last
[wantedCharacters release];
There are several mistakes in your code that causes you to lose the reference to the allocated objects, and an example will follow, but a few things:
The easiest solution for all of them, is to use autorelease wherever you call alloc (and remove the release for those objects), for example:
NSString* cleanStringOutput=[[[NSString alloc] initWithString:#""] autorelease];
When you create a variable only to assign to it later, there is no need to allocate, for example:
NSCharacterSet* wantedCharacters; // no need for alloc here
wantedCharacters=[ NSCharacterSet characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
In general - if you didn't allocate the object, you don't release it.
currentLetter=[NSString stringWithFormat:#"%c",[input characterAtIndex:i]];
Returns an autoreleased string - no need to alloc/init it above.
NSString* currentLetter =[[NSString alloc] initWithString:#" "];
So calling
[currentLetter release];
Will probably cause problems.
You alloc/init a wantedCharacters object, then reassign it using a convenience function. The reassignment creates a zombie with the first object.
The convenience function puts the new object instance into the autorelease pool.
Then you call release. Since it was only retained once, it gets deallocated.
Later, the autorelease pool calls release on it, but it has already been deallocated. This causes the crash.

iphone memory management and arrays

I'm still trying to wrap my head around iphone memory management. I have checked this with leaks but I want to make sure. Is this free of leaks?
NSMutableArray *array = [[NSMUtableArray alloc] init];
NSMutableString *str = [[NSMutableString alloc]];
[str appendstring:#"hi"];
[array addObject:str];
[str release]; //this is the bit I am most concerned about
...some processing of array occurs...
[array release];
Assuming your second line is actually this:
NSMutableString *str = [[NSMutableString alloc] init];
Then yes, this is free of leaks. When you add the string to the array, the array takes an ownership interest in the string, so the subsequent statement where you release your ownership of it is fine. It still exists in the array as expected.
When you release the array, it will take care of cleaning up its own references, including the one pointing to the string you put in it.
RULE OF THUMB, YOU MAY WRITE THIS ON STICKY NOTE AND STICK IT ON YOUR DESK
If you alloc, new, init or copying than you are the owner :)
You have to release it! no one will clean up for you.
** Example :
NSString *releaseMeLaterPlease = [NSString initWithString....];
If you create any other way such as in Example assume "bag" is some array,
NSString *dontReleaseMe = [bag objectAtIndex:0];
now, dontReleaseMe isn't create by alloc, new, init or copy so you don't release them. Some one will do it.
If you use autorelease after alloc and init than, OS will take care of releasing it.
MOST IMPORTANT: Now developer doesn't have to worry about these stuff!!! Hoooooray! Automatic Reference Counting is on from iOS5
However it is good to learn as not all devices has iOS5 :)
Good luck!
quixoto answered the question, but just for the sake of being explicit, here's what's going on with regard to memory management in your code on each line:
NSMutableArray *array = [[NSMUtableArray alloc] init]; //array retain count = 1
NSMutableString *str = [[NSMutableString alloc]]; //str retain count = 1
[str appendstring:#"hi"];
[array addObject:str]; //str retain count = 2
[str release]; //str retain count = 1
...some processing of array occurs...
[array release]; //array retain count = 0 & str retain count = 0 .. objects will be removed from memory.

iOS: understanding Problem with release an NSString

I have following code:
+ (NSDictionary*) JSONRequest: (NSString*)query andWithCredentials:(BOOL)withCredentials
{
if (withCredentials)
{
NSString *username = [LoginHandler GetUsernameFromNSDefaults];
NSString *password = [LoginHandler GetPasswordFromNSDefaults];
NSString *additionalQuery = [NSString stringWithFormat:#"login_username=%#&login_password=%#", username, password];
query = [NSString stringWithFormat:#"%#&%#", query, additionalQuery];
[username release];
[password release];
[additionalQuery release];
}
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:query]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *jsonString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
return results;
[request release];
[response release];
[jsonString release];
[results release];
}
The problem is the Release of the additionalQuery-NSString.
When I run this code, it ends with an BAD-ACCES-EXCEPTION for the
[additionalQuery release];
As soon as I comment this out, the code works fine.
Now, as simple as it is, run my app without this line of code could be fine, but my question is: What do Im wrong?
I generate an NSString in an IF-Clause, then I CAN only release it in the IF-Clause. But why I got a Error there?
Look at your creation of additionalQuery
NSString *additionalQuery = [NSString stringWithFormat:#"login_username=%#&login_password=%#", username, password];
With stringWithFormat you create an autoreleased NSString object. You MUST NOT release it manually according to the Memory Management rules since you don't own it.
You own only things you created with alloc] init..] or something with new.. or create.. in the name and of course if you do a copy such as mutableCopy.
So [additionalQuery release] causes over-releasing an object and thus it is a BAD ACCESS
The problem is that the string instance is created using a class method that starts with the class name (stringWithFormat). By convention, these types of class methods return an autoreleased object, freeing you from worrying about releasing them unless you specifically call retain on the returned object.
If you do want to perform your own memory management on the object, you could change your line:
NSString *additionalQuery = [NSString stringWithFormat:
#"login_username=%#&login_password=%#", username, password];
to either of the following:
NSString *additionalQuery = [[NSString alloc] initWithFormat:
#"login_username=%#&login_password=%#", username, password];
or:
NSString *additionalQuery = [[NSString stringWithFormat:
#"login_username=%#&login_password=%#", username, password] retain];
As an aside, you also have several other issues with this code.
The username variable should not be released because again, by convention, the method you get it from GetUsernameFromNSDefaults should return an autoreleased object. As a general rule of thumb, any method other than an init method should return an autoreleased object. It would become very difficult for a programmer not knowledgable with the codebase to pick it up and modify without following these conventions.
The request variable does not need to be released because it is created with a class method that returns an autoreleased object (requestWithURL). If you wanted it to be retained by your code, either call retain on it, or use the method initWithURL:.
Additionally, the results variable is not retained by you, so there is no need to release it.
You don't have to release it manually, it will get autoreleased. ([NSString stringWithFormat:] vs. [NSString initWithString:])
additionalQuery was never retained, that I can see. (stringWithFormat does an autorelease, so it doesn't count.)
When you create an instance of an object using a convenience method (one that does not begin with new, alloc or copy) the returned object is autoreleased. In other words you do not need to explicitly release it.
When you invoke the stringWithFormat method it returns an autoreleased NSString. You subsequently go on to release this NSString instance...
[additionalQuery release];
This sends the release message to the additionalQuery instance. As it's an autoreleased object it is added to an autorelease pool which lives (usually) on the main event thread. This pool is drained frequently and subsequently sends a release message to each of the objects it contains. Hence when an object is autoreleased the pool will look after sending the release message for you.
Your EXC_BAD_ACCESS here is a result of you releasing the NSString - dropping its retain count to 0 prior to the pool draining. The pool is then drained and attempts to send a message to a deallocated object.
you have specified here [NSString stringWithFormat:#"login_username=%#&login_password=%#", username, password];
means this method will handle allocation and release for your string so "you do not need to release it" hence remove the line [additionalQuery release];
also, u are not allocating string for username and password hence no need to release it .
if you write Nsstring *username = [[NSString alloc]init]; then you need to release it..
for more information regarding Memory Management refer
http://marcelsite.heroku.com/posts/5-iPhone-s-alloc-init-new-retain-release-autorelease-copy-
this will really help you...

Dealloc objects of another class

Hi I generally create objects of another classes. can you please tel me if this wil be in the auto release pool? or should we release it manually.
if you init copy or new them you'll have to deallocate them if you put an autorlease with the allocation then they will be autoreleased
for example
Foo *foo = [[Foo alloc] init]; //you'll have release it somewhere yourself
And
Foo *foo = [[[Foo alloc] init] autorelease];// this will be autreleased
The simple case is : if you use init, you are responsible for releasing it, either by calling release or by calling autorelease.
e.g.
NSString *myString = [NSString alloc] init]; // You need to release this
...
[myString release]; // Now it's released - don't use it again!
or if you are going give it to someone else
NSString *myString = [NSString alloc] init]; // This needs releasing
...
return [myString autorelease]; // You are finished with it but someone else might want it
However, there's a few other cases.
NSString *myString = [NSString stringWithFormat:#"hi"];
This object is in the autorelease pool already - don't release it!
NSString *secondString = [myString copy];
This object needs releasing - it is not autoreleased.
Rule of thumb : Anything with init, copy or new in the name - you made it, you release it. Anything else will be autoreleased.

Should I release a pointer that's pointing to an item in an array?

Not quite sure how to phrase this, but should I release a variable in this situtation:
NSString *string = #"HELLO WORLD";
NSArray *array = [NSArray arrayWithObject:string];
NSString *shouldIReleaseThis = [array objectAtIndex:0];
NSLog(#"%#", shouldIReleaseThis);
//???? [shouldIReleaseThis release] ??????
//Do stuff with array
Should I release it? Why or why not?
You don't own it (you didn't get that reference from new, alloc, retain or copy), so you shouldn't release it. See Apple's memory management programming guide for a brief but complete overview of the memory management rules in Cocoa.