Conditions in which retainCount increases or decreases - objective-c

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.

Related

Can an Objective-C object's retain count drop below zero?

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.

How is retain count implemented in NSObject?

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.

How does retainCount work?

I have a problem with retainCount
NSLog(#"%i", [self.albumReceiver retainCount]);
self.albumReceiver = [[[FacebookAlbumsDelegateReceiver alloc] init: self] autorelease];
NSLog(#"%i", [self.albumReceiver retainCount]);
The retain count on the first line is 0 but when it gets to third line is 3.
The property on self.albumReceiver is retain property... But as far as i can see it should be 2 where other later retain count should went to 1 since it was autorelease later.
NSLog(#"%i", [self.albumReceiver retainCount]);
albumReceiver = [[[FacebookAlbumsDelegateReceiver alloc] init: self];
NSLog(#"%i", [self.albumReceiver retainCount]);
the retain count start with 0 and in this case the second retain count print 2....
Can somebody give some idea of how this retain and release work....
I thought without 'self' keyword, it will ignore the setter call is it? But if i put autorelease on the second example, i will have error.
Firstly, the retain count is an implementation detail that you should not be overly concerned with. You should really only care about ownership.
Having said that, the explanation for what you are seeingis as follows:
The retain count on the first line is 0
That's because self.albumReceiver is nil at that point. On real objects, you will never see a retain count of 0 (in the current implementation of Foundation).
when it gets to third line is 3
Normally you would expect the retain count to be 2, +1 for the alloc and +1 for assignment to a retain property. However, the init: method might cause some other object to retain it, so might the setter for the property. Another object observing the property might choose to retain the object too. In short, unless you know the exact implementation of all the methods involved and you know for sure nothing is using KVO on albumReceiver, all you can say about the retain count is that self has ownership of it (NB ownership is not exclusive, other things may also have ownership). This is why you shouldn't pay too much attention to retain counts.
Can somebody give some idea of how this retain and release work
Yes. You need to think in terms of ownership. Certain methods give you an object that you own. These are any method starting with alloc, any method starting with new, any method starting with copy or mutableCopy and -retain. If you receive an object in any other way, you do not own it. That includes receiving them as a return result of a method, ass parameters of a method or as by reference parameters of a method or as global or static variables.
If you own an object, you must relinquish ownership by either releasing or autoreleasing it, or it will leak. If you do not own an object, you must not release or autorelease it.
I find that it is best to think of "you" in the above as meaning "the scope in which the object reference was declared".
Anyway, I recommend you to read Apple's Memory Management Rules for the definitive explanation and not to trust answers here. If you look at the original edit for this answer, you'll see that I got the rules slightly wrong because they have been tightened up since I last read them.
Do not use retainCount. (For situations where it’s appropriate to use it, see this website.) Further reading: blog post by bbum, previous SO thread one, thread two. Also note that retainCount is deprecated in recent SDKs. It’s a good idea to pay attention to the deprecation warnings, and even better idea to turn all warnings into errors.
It is generally a bad idea to pay any attention to the retainCount of an object in Objective-C because it is usually impossible to know which secret parts of the frameworks feel a need to retain the object.
In the case you cite where you are adding the object to the autorelease pool, the autorelease pool will presumably be retaining the object until it comes time to flush the pool (during the runloop). This probably explains why the retain count is higher for the autoreleased object.
Note the use of the words "presumably" and "probably" in the above paragraph. I have no idea if this is actually what is happening inside the Cocoa/Cocoa Touch frameworks. This is the problem with using retainCount, you have no way of knowing what the retain count should be at any moment.
If you retain the object (or create it with a method name that contains alloc, copy, mutableCopy or new), you release it. The frameworks are free to also retain the object and they will release it when they are ready. When the retain count reaches zero it will be dealloced.
Update: Having looked at the GNUStep source code for NSObject and NSAutoreleasePool my possible explanation above probably isn't what is happening. However, I have no way to check for sure because I can't see Apple's implementation of these two objects. Even more reason not to trust retainCount or any inferences from it.
The only rule that really exists in environments with manual memory management is
If you use alloc, copy, mutableCopy, new
release it. Otherwise DON'T. retainCounts don't really work for debugging. See here

About dealloc/release: is it always OK to do x = nil; [x release]; - or can it cause problems?

since every assignment to a variable with a different object increases its retain count and in the dealloc its not always clear how often a variable got assigned a simple [maVar release] might NOT BE SUFFICIENT. So using ALWAYS myVar = nil sets the retain count to zero, and a subsequent [myVar release] will never cause a problem again. (is it actually still required ?)
The only situation when not to do it this way is if myVar is passed OUT then I must not do this, since the value gets destroyed by myVar = nil;
Is my thinking correct? Or could this way of avoiding leaks cause any other problems?
Your thinking is incorrect in quite a lot of ways. These are probably just scratching the surface:
Assignment to a variable does not increase its retain count. (There are some subtleties to do with properties, but frankly that's way beyond the level we're at here.)
dealloc is called when the retain count reaches 0.
Setting myVar = nil does not affect the retain count.
myVar = nil destroys only the local pointer value, it does not destroy an object that has been passed out.
It is safe to call [myVar release] when myVar is nil, but it isn't useful -- it does nothing.
Worrying about retain counts is always a mistake. Worry about what you own.
It is clear that your grasp of C pointers and Objective-C memory management is a bit lacking. I'd suggest doing some remedial C work before several thorough re-reads of the Memory Management docs.
Please read Apple's documentation on Memory Management.
Assigning a pointer to an object will not increment the retain count, only calling retain does that. Functions with Copy or Init in the name should return an object with a retain count of 1, other functions should return autoreleased objects that will be dealloc'd when the main loop finishes.
Setting an object to nil doesn't modify the retain count, but it will cause that memory to leak. Calling release on the pointer at that point essentially does nothing. You need to be responsible about using retain, release, autorelease, and how you name your functions if you want to effectively manage your memory usage.

What is retainCount in Objective-C?

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.