tags:

views:

193

answers:

4

If I have this code

 NSString *postData = [@"foo=" stringByAppendingString:fooText.text];
 ...
 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
 ...
 [postData release];   //this causes crash
 [request release];    //this causes crash

Now I understand this is the expected behavior according to Apple's documents. Now if i remove the release code the crash doesn't happen but I find that the memory leaks anyway for *request. So I rewrite the code

NSString *postData;
//postData = [NSString alloc];  // this line commented out since OP
postData = [@"foo=" stringByAppendingString:fooText.text];
...
NSMutableURLRequest *request;
request = [NSMutableURLRequest alloc];
request = [request initWithURL:url];
    ...
    [postData release];   //this still crashes #
    [request release];    //this works fine

I don't really understand why it would crash at # . Is there any recommended best practice here? I think I must be missing something because I often see the 'shorthand' approach (top) having a release (Kochan, Programming in Objective-C for example), but the Apple docs say that it's wrong.

A: 

Allocating memory for your object and initializing it better perform in single line - init method may return different object and also it may help to avoid mistake you've made in 2nd example:

NSString *postData; // Define pointer to string
postData = [NSString alloc]; // Allocating nsstring pointer and assign it to variable
postData = [@"foo=" stringByAppendingString:fooText.text]; // assign to postData new **autoreleased** string object. result of the previous assignment is abandoned.
[postData release];  //so here you release autoreleased object!!

I cannot figure out why [equest release]; causes crash in the 1st example though.

P.S. I'm not completely wake up or it should be [postData release] instead of [release postData] ?

Vladimir
+7  A: 

The general rule of thumb, if you are calling a helper static method (such as stringByAppendingString), then you shouldn't release it. That string was added to an autorelease pool before being given to you. If you are calling alloc then an init... method, then you are responsible for releasing that object.

Other things to note in your code:

  • In the second example, you alloc postData, then immediately replace it with another string created by stringByAppendingString, that is a memory leak.
  • Your release calls are wrong, they should be [postData release] and [request release]
  • I don't see any correlation between postData and request in your example, so not sure exactly what you are getting at with the two of them.
Matt Greer
"The general rule of thumb, if you are calling a helper static method (such as stringByAppendingString), then you shouldn't release it." That was what I was looking for! However, how would I release the *request in the first example given that instruments was indicating that there was a memory leak (this is all inside a simple method). This would seem to indicate the autorelease wasn't working for *request.
Gazzer
In the first example, you allocated and initted request yourself, so you should release it. What is the crash you get when you do? EXC_BAD_ACCESS? That usually means you've (or something you gave request to) already released request and you didn't realize it.
Matt Greer
+1  A: 

First, in your second example, the line postData = [NSString alloc]; is completely unnecessary - postData is overwritten by the next line. Second, to answer your question as to why things crash - there is no good answer - the system can choose to free up memory anytime after the retain count hits 0. To more easily debug the issue, you should turn on NSZombieEnabled, which will immediately scribble any objects which are deallocated, giving you a 100% reliable way to test crashes.

Also, it is bad style to alloc/init on separate lines.

In general, you should focus on following the memory guidelines. If you're not following the guidelines, behavior can be undefined.

Mike
A: 
NSString *postData;
postData = [[NSString alloc]init];
postData = [@"foo=" stringByAppendingString:fooText.text];
...
NSMutableURLRequest *request;
request = [[NSMutableURLRequest alloc]initWithURL:url];
...
    [postData release];   
    [request release]; 

Try this.

Nithin
Your example still have same problems with postdata as in original question
Vladimir
its better to add [postData release]; as soon as you finished using that variable. You have to release memory after its use.
Nithin
postData contains autoreleased object after assignment in 3rd line - you must not release it. and you allocated string in 2nd line just leaks as you simply overwrite it.
Vladimir
NSString *postData = [[NSString alloc]init];postData = @"foo=%@",[fooText.text];this also might be used, note that this may not be the reason for your problem.
Nithin