Question

I have a class derived from NSThread:

@interface FSEventMonitorThread : NSThread {
    FSEventStreamRef m_fseStreamRef;
    CFRunLoopRef m_runLoop;
}

- (id) initWithStream:
    (FSEventStreamRef)fseStreamRef;

- (void) dealloc;

- (void) main;

@end

@implementation FSEventMonitorThread

- (id) initWithStream:
    (FSEventStreamRef)fseStreamRef
{
    if ( self = [super init] )
        m_fseStreamRef = fseStreamRef;
    return self;
}

 - (void) dealloc
{
    CFRunLoopStop( m_runLoop );
    FSEventStreamStop( m_fseStreamRef );
    [super dealloc];
}

- (void) main
{
    m_runLoop = CFRunLoopGetCurrent();
    FSEventStreamScheduleWithRunLoop(
        m_fseStreamRef, m_runLoop, kCFRunLoopDefaultMode
    );
    FSEventStreamStart( m_fseStreamRef );
    CFRunLoopRun();
}

@end

Elsewhere (inside a C++ function), I create an instance:

m_thread = [[FSEventMonitorThread alloc] initWithStream:m_fseStreamRef];

My understanding is that the retain-count should now be 1. In another C++ function, I want to stop and deallocate the thread:

[m_thread release];

Yet the dealloc method is not called. If I instead do:

[m_thread release];
[m_thread release];

then dealloc is called which implies the retain-count was 2. But how did it get to be 2?

Note that the documentation for NSThread only mentions retaining when using detachNewThreadSelector:toTarget:withObject:.

Was it helpful?

Solution

The framework itself keeps ownership of the thread. This is necessary so that the thread object doesn't go away while the main method is executing. If you want to stop a thread, you are doing it the wrong way. You must provide some sort of inter-thread communication to signal the thread's main method that it should stop whatever it is doing, clean up, and exit. Once that happens, relinquishing your ownership of the thread will cause the thread to dealloc. You should never simply over-release something to get it to "go away". If you are doing that, you are almost certainly not using the provided objects the way they are meant to be used, as in this case.

A very simple example to cancel your thread might be:

- (void)finishThread
{
  if( [NSThread currentThread] != self ) // dispatch this message to ourself
    [self performSelector:@selector(finishThread) onThread:self withObject:nil waitUntilDone:NO];
  else
    CFRunLoopStop(CFRunLoopGetCurrent());
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top