RetainCount == BAD
retainCount
is taboo, unreliable, unpredictable, and in general shouldn't be used. I don't use it anywhere in my code, but I have seen it in one class that I use in an interesting way.
I have a class that runs a thread that runs indefinitely until the thread is cancelled. The catch is that the thread increases the retain count of the owner, in my case the class that instantiated it. So, even if I am done using that class, that instance is still going to hang around unless whoever is managing my class also has the smarts to know to shut down the thread. That is one solution, but this is what I found in code.
- (oneway void)release
{
// This override allows allows this object to be dealloced
// by shutting down the thread when the thread holds the last reference.
// Otherwise, the object will never be dealloc'd
if (self.retainCount == 2)
{
[self quitDispatchThread];
}
[super release];
}
This is a clever solution, but I'm not sure what to think of it. It overrides release on the class and checks to see if the retain count is 2. In other words, it checks to see if the thread is the only thing keeping my object alive (since the retain count is about to be decremented from 2 to 1) and if it is, it terminates the thread (quitDispatchThread
will block until the thread is terminated).
So...
Can you rely on retainCount to see if it is one?
Usually people say to stay clear of retainCount
because you don't know if there are some autoreleases in there. However, if the retainCount is one then I know for a fact that only the thread is keeping it alive and I don't have to be concerned that the retainCount might be off due to some autoreleases, etc...
What's wrong with this code?
I was about to remove it, but it actually seems to make sense. Other objects don't have to have an awareness that my class is running a thread. Other objects can safely retain
and release
or even autorelease
the object owning the thread without having to worry about shutting the thread down because it takes care of itself.
This code actually feels clean, which surprises me.
Edit :: NSThread is Retaining my Object
The retain count of my object is increased by the fact I'm using NSThread. My object is the target
and the selector
is the method the thread runs on.
initWithTarget:selector:object:
Returns an NSThread object initialized with the given arguments.
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
Parameters
target
The object to which the message specified by selector is sent.
selector
The selector for the message to send to target. This selector must take only one argument and must not have a return value.
argument
The single argument passed to the target. May be nil.
Return Value
An NSThread object initialized with the given arguments.
Discussion
For non garbage-collected applications, the method selector is responsible for setting up an autorelease pool for the newly detached thread and freeing that pool before it exits. Garbage-collected applications do not need to create an autorelease pool.
The objects target and argument are retained during the execution of the detached thread. They are released when the thread finally exits.
NSThread
which retains thetarget
when you init it to a target, selector, argument. So... I don't think I can get around the circular ownership. However, there is exactly one place where this object (and its associated thread) get cleaned up as it is only used in one place in the code. I already have code in place to do this. I was even about to check in the change. However, as I reviewed the change, I had to ask myself why I was doing it, especially when I know it works. – Refer-[NSThread initWithTarget:selector:object:]
. In short, make the target something other than the thread's owner. – Kirtle