As many people have said, this is basically one of the best articles ever written, on any topic - ever - anywhere!
Rames - you know you're good - you are good!!! I can only add my thanks.
One suggestion, "Note that we are still responsible for doing the "release" in the "dealloc" method..."
Perhaps you should enlarge on this slightly so that people have the definitive explanation in one place; i.e. one would not (cannot) release unless it is of such and such type, etc. So, I suggest a small new subsection "releasing properly in dealloc".
Thank you very much for the tutorial. But there is something I don't understand. What is the difference between doing
Code:
[textValue retain];
[text release];
text = textValue;
and
Code:
[text release];
[textValue retain];
text = textValue;
The first one should be the correct one. But I don't see (logically) the difference. If you do first retain on textValue and then you release the variable text, can't it be that when you do text=textValue that the variable text is already deallocated (like the second one)?
Thank you very much for the tutorial. But there is something I don't understand. What is the difference between doing
Code:
[textValue retain];
[text release];
text = textValue;
and
Code:
[text release];
[textValue retain];
text = textValue;
The first one should be the correct one. But I don't see (logically) the difference. If you do first retain on textValue and then you release the variable text, can't it be that when you do text=textValue that the variable text is already deallocated (like the second one)?
Remember that the special situation we're discussing is when "text" and "textValue" point to the same object.
Suppose that we were the only one holding onto the object that "text" and "textValue" addresses. Thus, the reference count on that object is 1. In the first case, the "retain" increments the reference count to 2, the "release" decrements it to 1. The reference count never reaches zero, so the system doesn't deallocate the object.
In the latter case, the "release" decrements the reference count to 0, and then the retain tries to increment it to 1. Sounds the same, however, as soon as the reference count hits zero, the system deallocates the object. Deallocations aren't somehow "deferred until later" - they happen as soon as zero is hit. So, perhaps much later, you then try to access the value addressed by "text," and you get an exception. It's a hard-to-find bug.
If "text" and "textValue" point to different objects, then of course the "release" could cause the object addressed by "text" to be deallocated - that's entirely good and proper, and exactly what we want - in that case, the order doesn't really matter. It's only in this special "both point to the same object" case that the second order presents a problem - basically, it's a subtle bug. It isn't horribly likely to be triggered, since takes (effectively) something like:
Code:
self.xyz = self.xyz;
to trigger it, but it can happen if you do something like
Hi there,
First of all i want to join the round of applause for this clear and hour saving post. I still have one question about memory management that this post raise :
because you've broken rule # 1 - you allocated it, but you didn't release it. What you really need to be able to do is tell Objective C "I'm responsible for this object, so I want to release it, but I want the release to be delayed until whoever asked for this object has had a chance to use it."
I understand the issue, but suppose the calling function of getObject will be in charge of releasing the object, would that be an issue?
For example :
Code:
// The getter function
- (MyObject *)getObject
{
return [[MyObject alloc] init];
}
// The caller function
- (void)doSomething
{
MyObject *obj = [self getObject];
// Do something with obj
[obj release];
}
In that case we wouldnt have to use auto release, and we would know exactly when we release it. It might be a twisted way of programming, but id like to know if its a "clean" way of dealing with the issue, on a theoretical point of view.
Now, this was accurate, helpful, concise and thorough. Thank you very much for sharing this. It helped me clarify things and from what I've read, lots of other people too.
I wish you the best in all your endeavors.
Hi there,
First of all i want to join the round of applause for this clear and hour saving post. I still have one question about memory management that this post raise :
I understand the issue, but suppose the calling function of getObject will be in charge of releasing the object, would that be an issue?
For example :
Code:
// The getter function
- (MyObject *)getObject
{
return [[MyObject alloc] init];
}
// The caller function
- (void)doSomething
{
MyObject *obj = [self getObject];
// Do something with obj
[obj release];
}
In that case we wouldnt have to use auto release, and we would know exactly when we release it. It might be a twisted way of programming, but id like to know if its a "clean" way of dealing with the issue, on a theoretical point of view.
Thanks a lot!
Typically, you try not to create these kinds of special situations, because it's hard to remember the responsibilities. Joe Programmer who comes along after you is unlikely to realize that he has to release the object, because he's been so indoctrinated into The Three Rules.
If a callee creates an object, the autorelease pattern works just fine, of course - have the callee autorelease, and the object sticks around for the caller to use it and gets released later. The only "down side" to it is that the object may stick around longer than you like. If you were doing this inside a loop, for example, all the objects build up in the autorelease pool until you finally return from the message processing.
Situations where you should (or have to) use autoreleased objects and where you want to force those objects to get released on command are an application for your own autorelease pool.
Code:
- (void)doSomething
{
for (int i = 0; i < 100000; i++)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MyObject *obj = [self getAutoreleasedObject];
// Do something with obj
[pool drain]; // obj will be released here
[pool release];
}
}
In this case, the autoreleased objects get put into the autorelease pool we created, since it's the most "deeply nested" one. (There's still another one wrapping your message processing, but you can't get to that one.) When the pool is drained, all the objects that have built up inside it get released. Thus, this would release MyObject, plus any other autoreleased objects that might have been created during the call to getAutoreleasedObject.
In this situation, without the autorelease pool, you'd build up 100,000 instances of MyObject in the surrounding autorelease pool until you returned and it got drained. Here, you clean up after yourself on each iteration of the loop.
(Needless to say, you probably shouldn't be doing this kind of thing in a UI thread, but there are worker thread situations that resemble this.)
__________________
For a little fun, check out my Biorhythms app
now the line in view did load will call the setter,
first line in setter [textValue retain]; will increase retain to 1
second [text release]; will decrease it to 0
now we got no retain count??
now the line in view did load will call the setter,
first line in setter [textValue retain]; will increase retain to 1
second [text release]; will decrease it to 0
now we got no retain count??
If "textValue" and "text" refer to different objects, then [textValue retain] and [text release] obviously deal with different retain counts.
If "textValue" and "text" refer to the same object, then (since the object exists at the moment) its retain count must be non-zero before this code is executed. Thus, retaining it and then releasing it won't alter the retain count - it can't go to zero unless it was zero originally, and it can't be zero originally or it wouldn't exist.
__________________
For a little fun, check out my Biorhythms app
If "textValue" and "text" refer to different objects, then [textValue retain] and [text release] obviously deal with different retain counts.
If "textValue" and "text" refer to the same object, then (since the object exists at the moment) its retain count must be non-zero before this code is executed. Thus, retaining it and then releasing it won't alter the retain count - it can't go to zero unless it was zero originally, and it can't be zero originally or it wouldn't exist.
Thanks for your replay.
So, is my code for declaring a string and giving it an initial value is correct?
then yes, this is quite correct. The "property" declaration indicates that your class will retain the string, and the "synthesize" will automatically create the appropriate code to do just that.
Code:
self.text = @"hi";
will then call the synthesized "setter", causing the member variable to be set with a retained version of the string, releasing any prior contents.
You should also have a
Code:
[text release];
in your class's "dealloc" method in order to ensure that whatever string is assigned to "text" is properly released when your class instance is deallocated. If you don't do that, you will have a potential memory leak.
__________________
For a little fun, check out my Biorhythms app
I am trying to do a similar quiz app and wanted to put images to questions. For instance if its a sports question I would put a sports picture, music question pic of guitar, etc.
The first line creates an object. Since we "alloc'd and init'd" the object, it now has a retain count of one. Then we call the setter in the second line. The setter was presumably defined to retain the object, so that makes the retain count two. Then the third line releases the object once. This balances out the implicit retain in the first line, leaving the retain count at one, meaning that the only reference to the object is by the owner.
Why release obj surely the retained setter self.obj = obj, both releases and retains the pointer so the retain count remains at 1 not 2 and the final statement would reduce the retain count to 0 ?
Great post clear concise and thorough, Im currently busy swearing at several iPhone development books I wish you'd write a one !
I understood most of your posts but Im a little confused by the following
Why release obj surely the retained setter self.obj = obj, both releases and retains the pointer so the retain count remains at 1 not 2 and the final statement would reduce the retain count to 0 ?
Thanks
self.obj = obj will release the OLD pointer (the previous "self.obj") and then will retain the one being set. The idea is that it disposes of the object that was previously being held, then retains the new one.
__________________
For a little fun, check out my Biorhythms app
self.obj = obj will release the OLD pointer (the previous "self.obj") and then will retain the one being set. The idea is that it disposes of the object that was previously being held, then retains the new one.
Yes I understand that, as in this example from your tutorial
just to clarify my rather confusing question heres your post
Quote:
As a result of this, it is almost always better to use the "self.text =" form instead of the "text =" form - the latter is quite likely to generate memory leaks. To use the "text=" form properly, one would have to do:
Code:
in order to make sure that the memory was handled properly. But guess what? This is essentially identical to the setter that was automatically generated for us, so why not just do it as:
Code:
The first line creates an object. Since we "alloc'd and init'd" the object, it now has a retain count of one. Then we call the setter in the second line. The setter was presumably defined to retain the object, so that makes the retain count two. Then the third line releases the object once. This balances out the implicit retain in the first line, leaving the retain count at one, meaning that the only reference to the object is by the owner.
Let's walk through it line by line, expanding into the subroutine.
Code:
SomeObject *obj = [[SomeObject alloc] init];
At this point, "obj" has been created and has a retain count of 1.
When "self.obj = obj" gets executed, this results in:
Code:
[textValue retain];
At this point, "textValue" (the parameter to the subroutine) refers to the same object as "obj", so "obj" now has a retain count of 2.
Code:
[text release];
"text" does NOT refer to "obj" - it refers to whatever object was *previously* attached to the parent object. Thus, this decrements the retain count on the previous object, possibly releasing it, but does not alter obj's retain count.
Code:
text = textValue;
No alterations to the retain count.
Now we're back out of the subroutine
Code:
[obj release];
"obj" has its retain count decremented from 2 to 1.
Basically, "obj" starts with a retain count of 1 (from the alloc), and then has its retain count incremented when it is "attached" to "self". The retain count is then decremented with the explicit release. If I then did
Code:
self.obj = anotherObj
at that point, the "text" item inside the subroutine WOULD be referring to "obj" (since IT would now be the "old" object) and it would be released, decrementing its retain count to zero and causing the memory to be dealloc'd.
__________________
For a little fun, check out my Biorhythms app
Let's walk through it line by line, expanding into the subroutine.
Code:
SomeObject *obj = [[SomeObject alloc] init];
At this point, "obj" has been created and has a retain count of 1.
When "self.obj = obj" gets executed, this results in:
Code:
[textValue retain];
At this point, "textValue" (the parameter to the subroutine) refers to the same object as "obj", so "obj" now has a retain count of 2.
Code:
[text release];
"text" does NOT refer to "obj" - it refers to whatever object was *previously* attached to the parent object. Thus, this decrements the retain count on the previous object, possibly releasing it, but does not alter obj's retain count.
Code:
text = textValue;
No alterations to the retain count.
Now we're back out of the subroutine
Code:
[obj release];
"obj" has its retain count decremented from 2 to 1.
Basically, "obj" starts with a retain count of 1 (from the alloc), and then has its retain count incremented when it is "attached" to "self". The retain count is then decremented with the explicit release. If I then did
Code:
self.obj = anotherObj
at that point, the "text" item inside the subroutine WOULD be referring to "obj" (since IT would now be the "old" object) and it would be released, decrementing its retain count to zero and causing the memory to be dealloc'd.