views:

74

answers:

4

I'm wondering how bad is the following code for experienced objective-C programmers.

self.request = [[ASIHTTPRequest alloc] initWithURL:url];
[self.request release];

It is definitely less verbose this

ASIHTTPRequest *tmp = [[[ASIHTTPRequest alloc] initWithURL:url];
self.request = tmp;
[tmp release];

But I'm not sure if it is meaningful enough or doesn't lead to bugs.

What do you think?

UPDATE: I don't want to use autorelase pools as my app is going to run on iphone where memory is limited.

+1  A: 

Definitely go with the latter, although choose a more descriptive name instead of tmp. You are responsible for releasing tmp, but you are not responsible for releasing self.request, at least not in the context given.

Alternatively, if you don't mind adding things to the autorelease pool, simply do:

self.request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];

or

self.request = [ASIHTTPRequest requestWithURL:url];
dreamlax
I don't think adding to the autorelease pool is that big of a deal in this case, since the object won't actually be released. It's just a retain count decrement (not a free) since (presumably) the property assignment incremented the retain count.
Steve Madsen
Of course it will be released. It will be released when the autorelease pool gets drained. It won't get deallocated, provided that the property retains the request instance. It's more concise to use the autorelease pool, but at the cost of that tiny little bit of unnoticeable overhead.
dreamlax
You're right; poor use of terminology on my part. s/released/deallocated. My point was that adding it to the autorelease pool isn't using up memory that would otherwise be freed right that moment, because the property setter has likely retained the object. Adding to the autorelease pool in this case is only adding one more object to iterate when the pool is drained, which is insignificant. It's not changing the memory profile of the application unless the `self` object will also be released before the autorelease pool drains.
Steve Madsen
+1  A: 

Why not this?

self.request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];

Or, if this is a class you wrote or have the source for, create a new class method (not instance) that does essentially the same thing (assuming NSURL * argument):

+ (ASIHTTPRequest *) requestWithURL:(NSURL *)url
{
     return [[[self alloc] initWithURL:url] autorelease];
}
Steve Madsen
I agree completely. Using autorelease keeps everything clean and clear and on one line. If you're just doing normal things like setting up a view, I'd use autorelease. It's only in loops really that you have to worry about adding to the autorelease pool.
Felixyz
I'm coding for coca-touch where memory is quite important.
Piotr Czapla
Although even with memory constraints, adding something to the autorelease pool probably only involves copying a pointer (so that it knows where to send the `release` message). The iPhone OS autorelease pool is probably more likely to be conservative about increasing its capacity than the Mac OS X one.
dreamlax
+2  A: 

UPDATE: I don't want to use autorelase pools as my app is going to run on iphone where memory is limited.

Do use the autorelease pools! Cocoa touch framework itself uses them; making one or two autorelease'ed objects yourself doesn't change the big picture.

It's true Apple warns you against excessive reliance on autorelease pools on iPhone, like putting hundreads of objects before the pool gets drained after the conclusion of the event dispatch, but excessive avoidance of autorelease pools is also counter-productive!

Nothing is black and white; nirvana is in the middle way.

Yuji
What do you say about this post on:http://stackoverflow.com/questions/155964/what-are-best-practices-that-you-use-when-writing-objective-c-and-cocoa#answer-175874
Piotr Czapla
I also agree with what mmalc wrote there; mmalc is definitely one of the well-known Cocoa gurus. (Google mmalc.) But again, nothing is completely black or completely white; it really depends how many `ASIHTTPRequest` object you create and destroy in one event loop. There's no firm fixed rule. If a person asks if s/he should always avoid autorelease, I would recommend to use autorelease; if a person asks if s/he should always make autoreleased objects, I would say to avoid relying on autorelease too much. When in doubt, measure it with Instruments.
Yuji
I agree, as well, but in this particular circumstance, consider the bigger picture of what you're doing. Your setter is probably retaining the object. Unless `self` is very short-lived itself, this `ASIHTTPRequest` object isn't dead memory piling up in the autorelease pool. It's in-use memory, merely waiting for a delayed retain count decrement to happen. Yuji's advice is really the key: measure before you start worrying about it. You're already using autoreleased objects all over (`stringWithFormat:` etc.). Don't sweat another one unless you prove to yourself that it's hurting performance.
Steve Madsen
He asked what do you think about directly assigning to a property and then releasing it. In my opinion that has nothing to do with autorelease. The answer should explain that `releaseing temp` does not actually release property because there is a strong possibility that the object retained the value. What is being released here is the temporary reference that was used to setup the object before passing it to another object.
stefanB
A: 

What you missed is not the difference in verbosity but the memory management difference.

You often see code like this:

ASIHTTPRequest * requestTmp = [[[ASIHTTPRequest alloc] initWithURL:url];
self.request = requestTmp;
[requestTmp release];

You should consider what is happening if the property is retained and old one released in the setter method.

  • What this mean is that you create new request, refcount is 1.
  • self.request = request, now if setRequest looks like:

    - (void)setRequest:(ASIHTTPRequest*)aReq
    {
        [aReq retain];
        [request release];
        request = aReq;
    }
    

    This means that the object retained the requestTmp you passed in and released the old one. Refcount of requestTmp is now 2.

  • After this call you can then release your original requestTmp that you created and you are safe because the object retained the requestTmp - refcount is still 1.

However if you do this:

self.request = [[ASIHTTPRequest alloc] initWithURL:url];
[self.request release];

you end up releasing the request that the object retained for its use. Note that you are release object's internal request where in the original case you released the tmp but the object keeps it's own retained reference.

So the result is different from the original code.

stefanB
I've thought that ref counter is associated with the object not the instance variable. Are you sure that there is any difference in memory management between this two examples?
Piotr Czapla
My understanding is that: self.request = [[ASIHTTp.... makes an object with refcount=2 (one for alloc and one for [self setRequest]) and then releaseing self.request decrease the refcounter to 1. So we end up with exacly the same situation. as in the case of second more verbose code.
Piotr Czapla
Actually, this example depends very much on the implementation of the property getter. If it's a standard implementation or synthesized, the two examples here are identical. If the getter is a custom implementation and, for example, returns an autoreleased copy of the object, only then will the release go to a different instance (and in fact it would be released one too many times in this case; a property getter does not transfer ownership of the object).
Steve Madsen
I said `IF` the setter is implemented with `release/retain` ... since we don't see the code we can't tell. But `IF` it is using retain `THEN` those 2 code examples are different from the memory management point of view. Secondly, the original code above is often used in cases where the setter `retains` the value, e.g. you create object, set it up then pass it to another object, after that you `release` your reference. If you ask `experienced` coder then that's what you would expect the code will do. He did `NOT` ask what the code actually do, he asked what it looks like to us. Hence my answer.
stefanB