From a related thread, how should I have known the "mailString" below was already autoreleased?
//
+ (void) sendEmail:(NSString *) subject withBody:(NSString *)body {
NSString *mailString = [NSString stringWithFormat:#"mailto:?#&subject=%#&body=%#",
[subject stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding],
[body stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:mailString]];
[mailString autorelease];
}
stringWithFormat: is a convenience function that returns an autoreleased object.
I cannot recomment the Memory Management Guide highly enough. It really is worth reading, probably more than once.
since mailString is not created by the [[NSString alloc] init]; idiom it does need to be released.
You do not know that the object has been autoreleased.
All you know is that it is not your responsibility to release it.
You know that because it was returned to you from a method whose name did not begin with 'alloc', 'new', or contain 'copy', and you have never called 'retain' against it.
Reiterating what Eiko said - read Apples Memory Management Guide - it is very clear on this topic.
Related
This is my first post so I hope the formatting is ok.
I'm getting this leak "Potential leak of an object on line" and I can't figure it out. Perhaps I'm looking at it too hard and therefore I can't see the problem. Could someone help me out?
The line is question is: appDelegate.imageText
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
PListFirstAppDelegate *appDelegate = (PListFirstAppDelegate *)[[UIApplication sharedApplication]delegate];
appDelegate.imageText= [[NSString alloc]initWithFormat:#"%#",[[array objectAtIndex:indexPath.row]objectForKey:#"image"]];
//NSLog(#"%#", appDelegate.imageText);
NavigationalDescription *detailViewController = [[NavigationalDescription alloc] initWithNibName:#"NavigationalDescription" bundle:nil];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
Every time you use any init method to instantiate an object, you must release it somewhere, or call autorelease.
Class methods that return something should always be autoreleased.
So instead of using [[NSString alloc] initWithFormat...]
do [NSString stringWithFormat:#"%#", myString] instead.
Replace code at
appDelegate.imageText= [[NSString alloc]initWithFormat:#"%#",[[array objectAtIndex:indexPath.row]objectForKey:#"image"]];
with
appDelegate.imageText= [NSString stringWithFormat:#"%#",[[array objectAtIndex:indexPath.row] objectForKey:#"image"]];
You should add an autorelease call at the end of that line.
iPad won't let me copy paste code :( so no example right now.
appDelegate.imageText= [[[NSString alloc]initWithFormat:#"%#",[[array objectAtIndex:indexPath.row]objectForKey:#"image"] ] autorelease];
You are saying delegating control over the memory management to the imagetext instance. They should retain the string as they need it.
appDelegate.imageText= [[NSString alloc]initWithFormat:#"%#",[[array objectAtIndex:indexPath.row]objectForKey:#"image"]];
you are assigning an allocated string to image text property. the property assignment should be to an autoreleased string. imageText should be a retain property, therefore retaining the falue of the string being assigned to it. If it's retain, you are double retaining, therefore leaking the object.
I'm a newbie when it comes to objective C, and am currently experiencing a memory leak with the following code snippet. The memory leak occurs with the 'responseObj' allocation. Whenever I try to release it similar to responseData, I get a crash.
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString* responseStr = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSMutableArray* responseObj = [responseStr objectFromJSONString];
[delegate loadGameDetails:[responseObj objectForKey:#"result"]];
[responseStr release];
[responseData release]; responseData = nil;
}
I also tried to autorelease as below, but I also get a crash:
[delegate loadGameDetails:[[responseObj objectForKey:#"result"] autorelease]];
What's the proper way for me to release this block of memory?
The problem is not in your allocation. Your are sending objectForKey: to a NSMutableArray which is actually a NSDictionary/NSMutableDictionary method. Double check what type of object objectFromJSONString really returns.
Nothing in that code is leaking. You have a possible over-release of responseData but I can't tell since the declaration and setup of it is not in scope. If it is an ivar you would typically set it to nil via the accessor (which would release it there) than directly as you have done here.
If there is a leak it is in your loadGameDetails method. What makes you think you have a memory leak? Have you run this through instruments, or used the static analyser?
After trying to print retainCount of object I get 2147483647. Why do I get such a result? It should be 1, shouldn't?
NSString *myStr = [NSString new];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
2011-09-08 17:59:18.759 Test[51972:207] refCount = 2147483647
I use XCode Version 4.1. Tried compilers GCC 4.2 and LLVM GCC 4.2 - the same result.
Garbage Collection option was set to unsupported.
NSString is somewhat special when it comes to memory management. String literals (something like #"foo") are effectively singletons, every string with the same content is the same object because it can't be modified anyway. As [NSString new] always creates an empty string that cannot be modified, you'll always get the same instance which cannot be released (thus the high retainCount).
Try this snippet:
NSString *string1 = [NSString new];
NSString *string2 = [NSString new];
NSLog(#"Memory address of string1: %p", string1);
NSLog(#"Memory address of string2: %p", string2);
You'll see that both strings have the same memory address and are therefore the same object.
This doesn't directly answer your question, but retainCount is not really all that useful and should not be used for testing. See this SO post for details.
When to use -retainCount?
While NSString's are an odd case (there are others in the framework) you might also run across this in other clases - it's one of the ways of creating a singleton object.
A singleton only exists once in the app and it's pretty important that it never gets released! Therefore, it will overwrite some methods of NSObject including (but not limited to):
- (id)release {
// Ignore the release!
return self;
}
- (NSUInteger)retainCount {
// We are never going to be released
return UINT_MAX;
}
This object can never be released and tells the framework that it's a singleton by having a ludicrously high retain count.
Checkout this link for more information about singleton objects.
I've seen this a couple of times regarding NSStrings, the retainCount returns the maximum count instead of the actual one when you try to look at retainCounts of strings in this manner.
Try this;
NSString *myStr = [[NSString alloc] init];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
Edit: Restored NSUInteger
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...
If I have a method
- (void) myMethod:(NSString *)string {
[Object anothermethodWithString:string];
}
and I call
[Object myMethod:#"this is a string with no alloc statement"]
Do I need to do something like
- (void) myMethod:(NSString *)string {
NSString *string2 = [[NSString alloc] initWithFormat:#"%#", string];
[Object anothermethodWithString:string2];
[string2 release];
}
instead of the way I had myMethod before? I have misbehaving code that seems to be caused by a string being auto-released while a second method within another method is being called (like in the example). The second way I have myMethod fixed all of my problems.
So is a "non-alloc" string an auto-released string? I asked this question as a follow up to another question (which was completely unrelated and is why I am creating this post), and a few sources said that I don't need to reallocate the string. I am confused, because the behavior of my code tells me otherwise.
Dave's got it right. You only need to worry about calling release on objects that you new, alloc, retain, or copy.
The above rule works very well, but if you're curious and want to get into a lot of detail, I suggest reading the Memory management Programming Guide from Apple's docs. It's free and goes from basic concepts into a lot of details.
If you use : NSString *str = #"". It is kind of a constant, you don't need to do any memory management.
If you call from a method : NSString *str = [NSString stringWithFormat:#""], the str is already autoreleased.
If you manually alloc, init. You need to call release, or autorelease yourself.
The general memory convention is : if you do something with new, alloc, retain, or copy, you need to release it yourself, any other cases, the object is autoreleased, don't release it