I have learned manual memory management in Objective-C and every article said: "When the retain count of an object drops to 0, the dealloc method is called and the object is destroyed". And nothing more.
But there is no answer for several questions: Can I drop the retain count below 0? Is it possible to call [object release] several times in a row, before the object dies, and cause the retain count to drop below 0? And if I've done so, will the Universe still exist?
Google gives me nothing, like: "Why would you even ask this question? Nobody cares. Go and read about memory management once more."
If you call release when the retain count is 1, dealloc is immediately called. So the retain count doesn't ever even get to 0.
Further calls to release will cause a runtime crash as you would be dereferencing a deallocated object.
So no, the universe won't exist at that point :)
A retain count can be 0 or higher but never less. When an object is allocated heap memory (alloc init) the retain count is set to 1. You can then increase the retain count by calling retain on it (as far as I'm aware an unlimited number of times but I could be wrong).
Calling release simply decreased the retain count by 1. The system then periodically checks the retain counts of objects and deallocates any with a count of 0.
Calling release on an already deallocated object is the same as calling any method on a NULL object and should simply return NULL or void. However, if you are explicilty managing heap memory then you should be VERY aware of what you're doing.
Some interesting points:
Why can a retain count be more that 1?
This is so that an object isn't released whilst it is still required by something else. E.g. say you have pet owner and vet. A pet instance is owned by an owner instance. The owner goes to a vet instance and the vet takes ownership of the pet also. For a period of time pet has two owners and therefore (if retain has been called) has a retain count of 2. Lets say that the owner is then released before the vet has finished with the pet; if everything has been done properly the pet wont be deallocated it will simply have its reatain count decreased to 1 by the call to release from owner. The vet can then finish with the pet, call release and the pet will be deallocated.
ARC
As I'm sure you're aware this has all been replaced by Automatic Reference Counting. As developers we now have to simple be aware of the type of relationship an object has with another.
Therefore if you create an object now it will be deallocated when it fall out of scope unless it has a strong relationship (is owned) by another object. You can still get reatain cycles where two objects have strong relationships to each other and therefore never qualify for deallocation.
Appologies for the very long winded answer but memory management is a core part of application programming and is very interesting.
Related
My question is how the current versions of Foundation (or of the Objective-C runtime library, since this seems to be there) implement retain count for NSObject derived objects? As I could see at NSObject.mm, there is no ivar called retain count in the NSObject's interface body. Instead, there seems to be a kind of table or map which contains references counters for each object. But if retain count is really done with a map, aren't retain and release operations too expensive with this kind of implementation (since, in this case, it's necessary to lock and unlock mutexes, lookup the map to find the right object, besides the fact that, in a multithreaded environment, only one object can be retained/released at a time)?
I didn't find anything related to setting the retain counter to 1 when allocating a new object, neither in _objc_rootAllocWithZone at NSObject.mm (which seems to be the function that is called by [NSObject alloc]) nor in _class_createInstanceFromZone at objc-runtime-new.mm (that gets called later by _objc_rootAllocWithZone).
The retain count for NSObject is indeed kept in a global map. IIRC it actually uses a set of maps that are partitioned, presumably based on the address of the object, to reduce lock contention, but the actual implementation details are just that, implementation details.
In any case, you can't find code that sets the retain count to 1 because there isn't any. Objects with a retain count of 1 aren't put into the map. Objects only enter the retain count map when they're retained past the initial 1. This is an optimization that speeds up the common case of objects that never have their retain count rise past 1.
I have read that objects retain count and that it can be increased when we assigned a second value (or object).
Can anybody give me an idea about the basic conditions where retainCount increases or decreases (without retain , alloc and release)...
Short answer: no.
Slightly longer one:
Actions on your part that are typically expected to modify the retain count are retain, release, autorelease and calling methods whose name contains new or copy. In some instances, however, they might not do so, for good implementation reasons, but do something else instead. And there are many other things you can do, like adding objects to collections, that may modify the retain count in ways that are just not your business.
Do not use or rely on retain counts. They are an implementation detail.
Your concern is to manage your own ownership, which you do via the semantics of the above-mentioned methods. How that affects the retain count beneath the hood is something you are better off not even looking at.
Please just don't.
Being concerned about retain count is almost always a way to cause bugs, not cure them.
The retain count of an object is an implementation detail that you shouldn't worry about. You should really only concern yourself with when you gain and lose ownership of an object. Here's why:
+alloc returns an object with a retain count of 1. However, you immediately send it an init message which might give you back a completely different object. For instance
NSString* foo = [[NSString alloc] initWithString: #"foo"];
Gives you an object with a retain count of 1, right? Wrong on current implementations of Cocoa. The string returned by +alloc is immediately released and instead a reference to #"foo" is returned. The retain count of #"foo" is INT_MAX.
Retaining an object increases its retain count, right? Probably, but again sending retain to constant strings has no effect and some singletons have a nul implementation of retain too.
Similarly release usually has an effect on the retain count, but again not necessarily for the same reasons.
Sending copy should give you a new object with a retain count of 1 right? Wrong. Immutable objects can implement copy by sending themselves retain and then returning themselves. In most cases, that will add one to the retain count, but of course with string constants, nothing happens.
If you just think in terms of retaining and releasing ownership all of that stuff I have just said becomes irrelevant implementation details.
retainCount of an object changes in the following cases:
When you create an object(new or
alloc, copy or mutablecopy), it has a
retain count of 1.
When you send an object a retain
message, its retain count is
incremented by 1.
When you send an object a release
message, its retain count is
decremented by 1.
When you send a autorelease message
to an object, its retain count
will be decremented by 1(not
immediately as in case of release but
some time in the future)
You can view this post to get a detailed info on how memory management works in iPhone.
I want to ask about the iPhone application and objective C question. In the implementation program, there are function called 'dealloc', does this function only be called one time by the application?
For example, if I alloc a object and retain it 2 times, the retains count is 2 and I never use 'release' in the program, unless in the dealloc. Will the object be removed from the memory, or the objective will be removed from the memory. Thank you.
In the implementation program, there are function called 'dealloc', does this function only be called one time by the application?
Yes. -dealloc destroys the object. Trying to send any message to it again, including -dealloc is an error.
if I alloc a object and retain it 2 times, the retains count is 2
Careful. The retain count is at least 3. Other things than your code might retain the object. It's better not to worry to much about retain counts and only think in terms of ownership.
Each alloc, new, copy or retain is an claim of ownership. The object's dealloc method will only be called when all claims of ownership have been relinquished. A claim of ownership is relinquished by sending -release. So if you never release an object except in its own dealloc, you'll never release it.
dealloc is called once by the system when the object is destroyed (when its reference count reaches 0). If you have member variables in your class that you alloc in your init function, you must release them in your dealloc function.
If you give someone a pointer to one of those member objects and they retain it, the member could survive the release in your dealloc, but by sending a retain message they are taking responsibility for sending a release message later, ensuring its eventual destruction.
I recently took an objective-c test to see how I would do.
Turns out my score wasn't anywhere near as good as I hoped. That means more studying.
During the test, I was asked this question:
How do you free an object?
A. [obj dealloc];
B. [obj release];
C. None of the above
My choice was A, and I don't know if it's correct. The question is confusing: Doesn't release call dealloc, therefore achieving the same result?
No. release decrements the object's reference count.
You don't call dealloc directly. Call release to decrement the reference count and let the runtime call dealloc when the reference count becomes zero.
Yes, release does call dealloc but only after decrementing the reference count and only if the reference count went to zero. The NSObject class reference says that release:
"Decrements the receiver’s reference count."
"The receiver is sent a dealloc message when its reference count reaches 0."
I know an answer has already been accepted for this, but I can't resist adding my own thoughts.
The answer to the test question is technically C. You don't free objects, the runtime frees them when it thinks they are no longer in use.
If you release an object in the reference counted environment, you are not freeing it, merely indicating that you are relinquishing any claim of ownership. When nobody has an ownership claim, dealloc is called by the runtime and the object is freed. Similarly, in the garbage collected environment, when you overwrite a reference, you are signalling that you are no longer interested in it. Once all references have gone, at some indeterminate time later, finalize is sent to the object and the object is freed.
I have a UITableView as my first screen with a UINavigation controller.
In my first screen I NSLog(#"Home Screen retain Count=%d",[self retainCount]); and it logs 6 in when its viewDidLoad is called.
Is this correct?
The retainCount is the number of ownership claims there are outstanding on the object.
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. All of these increment the retainCount.
You relinquish ownership with using “release” or “autorelease”. These decrement the retainCount.
However you should never pay any attention to the value of retainCount, it is at best confusing, at worst misleading. Simply follow the memory management rules - take ownership when you need to keep a reference to an object and relinquish ownership when you are finished, and you wont have a problem.
If you are looking at retainCount, you are going about things the wrong way, and you will simply confuse yourself further.
It sounds fine. Why would it be wrong?
In general, trying to determine things from the retain count is a bad idea. There are no rules about the amount of times you can retain an object. The only rule is that each retain must be balanced with a release.