0

I'm creating a new thread using detachNewThreadSelector ref with toTarget self.

The purpose of the thread is to poll movements and load images as appropriate - it loops and only quits when an atomic bool is set to true in the main thread - which is set in the objects dealloc.

The problem is caused by this (from the detachNewThreadSelector reference):

The objects aTarget and anArgument are retained during the execution of the detached thread, then released

Which means my object will always have a (minimum) retain count of one - because the thread continuously polls. dealloc is therefore never called.

So my question is: how can I dealloc my object taking into account the existence of the polling thread?

The only idea I have right now is to create a destroyThread function of the object, which sets the end thread bool, which would be called from everywhere I'd expect the object to be destroyed. This seems error-prone, are there better solutions?

Thanks in advance.

Update

I had an idea for another solution - in the thread I detect if the retain count is one - if it's one then I know the thread is keeping the object alive, so I break the loop and dealloc is called. Is this a robust solution?

Community
  • 1
  • 1
CiscoIPPhone
  • 9,457
  • 3
  • 38
  • 42

1 Answers1

2

First, avoid detachNewThreadSelector:. Anything you are thinking of doing with it is almost certainly done better with a dispatch queue or NSOperationQueue. Even if you need to manually create a thread (which is exceedingly rare in modern ObjC), it is better to create explicit NSThread objects and hold onto them rather than using detachNewThreadSelector: which creates a thread you can't interact directly with anymore.

To the specific question, if you create your own threads, then you'll need to set that bool somewhere other than dealloc. That means that some other part of the program needs to tell you to shut down. You can't just be released and automatically clean yourself up using manual threads this way.


EDIT: Never, ever call retainCount. No solution involving retainCount is a good solution. Putting aside the various practical problems with using retainCount in more general cases, in this case it ties you manual reference counting. You should switch to ARC as quickly as possible, and retainCount is illegal in ARC (it should have been illegal before ARC, but they finally had a really good excuse to force the issue). If you can't implement your solution in ARC, it is unlikely a good solution.

Again, the best solution is to use GCD dispatch queues (or operations, which are generally implemented with dispatch queues). It is incredibly more efficient and effective for almost every problem than manual thread management.

If you must use a manual thread for legacy code and need to maintain this kind of auto-destruct, the solution is a helper object that owns the thread. Your object owns the helper object, which has a retain loop with the thread. When your object is deallocated, then it tells the thread to shut down, which breaks the retain loop, and the helper object goes away. This is a standard way of managing retain loops.

See Apple's Migrating Away From Threads for more.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • I really dislike the idea of manually shutting down the thread because it means I potentially need to modify the code wherever release is called on my object (however I up-voted for your other advice). I had an idea for another solution - in the thread I detect if the retain count is one - if it's one then I know the thread is keeping the object alive, so I break the loop and dealloc is called. What do you think about that solution? – CiscoIPPhone Jul 19 '12 at 19:40