2010-01-11 5 views
3

J'écris une application qui doit communiquer avec un appareil connecté via USB. L'application envoie et reçoit des données à tour de rôle à partir de l'appareil selon un calendrier fixe. Tout Rx/Tx se passe dans un thread séparé, sinon l'interface utilisateur serait bloquée. La structure de base ressemble fondamentalement à ceci. (Piscines autorelease et des trucs omis)Comment puis-je quitter [NSRunLoop runUntilDate]?

-(void)comThread:(id)arg { 
    while(state == kIsConnected) { 
    // let timers run 
    [runLoop runUntilDate:[NSDate distantFuture]]; 
    // handle data 
    if(rxTxState == kRx) { 
     // do some stuff to pass data to upper layers 
     rxTxState = kTx; 
    } 
    if(rxTxState == kTx) { 
     // do some stuff to send data 
     rxTimeoutTimer = [NSTimer scheduledTimer....]; 
    } 
    } 
} 

Après l'envoi de données, le délai d'attente pour les applications soit données à recevoir ou rxTimeoutTimer au feu qui conduit à la retransmission du paquet. L'opération rx fonctionne puisque les couches sous-jacentes utilisent des appels système async et appelle un gestionnaire rx qui ressemble à ceci.

-(void)receiveData:(NSData*)data{ 
    [rxQueue addObject:data]; 
    [rxTimeoutTimer invalidate]; // cancel timeout 
} 

est-il un (facile) façon de faire la sortie [runLoop runUntilDate:] de receiveData:? Les docs Apple disent que supprimer toutes les sources de minuterie ne garantit pas la sortie du RunLoop. J'ai lu quelque chose à propos de l'appel performSelector:onThread:... mais cela n'a pas fonctionné ou je n'ai pas compris le point.

Merci.

Répondre

9
CFRunLoopStop([runLoop getCFRunLoop]); 
+0

Ou, sans la variable locale 'runLoop': CFRunLoopStop ([[NSRunLoop currentRunLoop] getCFRunLoop]); – rpj

+3

@rpj: Vous utilisez 'CFRunLoopGetCurrent()' dans ce cas :) – kennytm

4

Le modèle standard consiste à exécuter le runloop pendant une certaine période de dépassement de temps (par exemple 0,5 seconde), puis effectuer une itération jusqu'à ce que la tâche est accomplie:

while(state == kIsConnected) { 
    while(!iterationDone) { 
    [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]]; 
    //do other stufff 
    } 
} 

-(void)receiveData:(NSData*)data{ 
    [rxQueue addObject:data]; 
    [rxTimeoutTimer invalidate]; // cancel timeout 
    iterationDone = YES; 
} 
+0

Le délai total est de 0,5 seconde dans mon cas. Je devrais exécuter le RunLoop pendant des fractions de ce temps comme 0.05 secondes. Je me demande si cela a vraiment cette résolution. – insanelygreat

+0

Il a vraiment cette résolution. – rpj

0

CFRunLoopStop ([runloop getCFRunLoop]) ; et CancelPerformSelector

didnot travail pour moi, Voir mon code pour l'exécution de [NSRunLoop currentRunLoop]

timerUpdateLocation = [NSTimer scheduledTimerWithTimeInterval:[time intValue] target:self selector:@selector(startTrackingBg) userInfo:nil repeats:YES]; 
[[NSRunLoop currentRunLoop] addTimer:timerUpdateLocation forMode:NSRunLoopCommonModes]; 
[[NSRunLoop currentRunLoop] run]; 

pour l'arrêter invalident I Just timer.

[timerUpdateLocation invalidate];

0

Faites comme ceci peut sortir. mais il va sortir après quelques secondes.

-(void)comThread:(id)arg { 
     BOOL ret = YES; 
     rxTimeoutTimer = [NSTimer scheduledTimer....]; 
     while(ret) { 
     // let timers run 
     ret = [runLoop runUntilDate:[NSDate distantFuture]]; 
     } 
    } 
    -(void)receiveData:(NSData*)data{ 
     [rxQueue addObject:data]; 
     [rxTimeoutTimer invalidate]; // cancel timeout 
     iterationDone = YES; 
    } 

la réponse de kennytm semble correcte.