2009-12-08 12 views
0

J'ai une classe dérivée de NSThread:Objet NSThread conservé deux fois?

@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 

Ailleurs (dans une fonction C++), je crée une instance:

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

Ma compréhension est que le retenir comptage doit maintenant être 1. Dans une autre fonction C++, je veux arrêter et désaffecter le fil:

[m_thread release]; 

Pourtant, leLa méthoden'est pas appelée. Si je place:

[m_thread release]; 
[m_thread release]; 

alors dealloc est appelé ce qui implique le retenir comptage était 2. Mais comment est-elle d'être 2?

Notez que la documentation pour NSThread mentionne uniquement la conservation lors de l'utilisation de detachNewThreadSelector:toTarget:withObject:.

Répondre

3

Le cadre lui-même conserve la propriété du fil. Ceci est nécessaire pour que l'objet thread ne disparaisse pas pendant l'exécution de la méthode principale. Si vous voulez arrêter un thread, vous le faites dans le mauvais sens. Vous devez fournir une sorte de communication inter-thread pour signaler à la méthode principale du thread qu'il doit arrêter tout ce qu'il fait, nettoyer et quitter. Une fois que cela se produit, abandonner votre propriété du thread entraînera le désengagement du thread. Vous ne devriez jamais simplement sur-relâcher quelque chose pour le faire disparaître. Si vous faites cela, vous n'utilisez presque certainement pas les objets fournis de la façon dont ils sont destinés à être utilisés, comme dans ce cas.

Un exemple très simple d'annuler votre fil pourrait être:

- (void)finishThread 
{ 
    if([NSThread currentThread] != self) // dispatch this message to ourself 
    [self performSelector:@selector(finishThread) onThread:self withObject:nil waitUntilDone:NO]; 
    else 
    CFRunLoopStop(CFRunLoopGetCurrent()); 
} 
+0

CFRunLoopRun() ne retourne pas avant CFRunLoopStop() est appelée; par conséquent, mon main() ne peut pas vérifier isCancelled. J'ai passé outre la méthode cancel pour appeler CFRunLoopStop(). Donc maintenant, pour arrêter le thread, je fais [m_thread cancel] suivi de [m_thread release] et ça marche. Question: est-ce que la méthode annuler est une chose OK à faire? La documentation ne dit pas que l'on ne devrait pas. –

+0

Cela dépend de ce que vous faites, mais en général, je dirais non, ne faites pas cela. Le moyen le plus simple de le faire serait d'ajouter une méthode comme finishThread; Je vais ajouter un exemple rapide à ma réponse. Vous devriez également faire le nettoyage dont vous avez besoin après le retour de la fonction CFRunLoopRun(). –