2015-10-04 3 views
1

Nous devons capturer stdout dans iOS parce que nous utilisons un projet open source qui communique via stdin/stdoutImpossible d'obtenir NSFileHandleDataAvailableNotification au feu pour les tuyaux stdout

Cela fonctionne:

NSPipe *pipe = [NSPipe pipe]; 
NSFileHandle *readh = [pipe fileHandleForReading]; 

dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout)); 

[@"Hello iOS World!" writeToFile:@"/dev/stdout" atomically:NO encoding:NSUTF8StringEncoding error:nil]; 

NSData *data = [readh availableData]; 
NSLog(@"%d", [data length]); 
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
NSLog(@"%@%@", @"stdout captured:", str); 

La console imprime:

2015-10-04 12:03:29.396 OpeningExplorer[857:42006] 16 
2015-10-04 12:03:29.397 OpeningExplorer[857:42006] stdout captured:Hello iOS World! 

Cependant, l'exemple ci-dessus est bloqué. Pourquoi le code asynchrone suivant ne fonctionne-t-il pas?

NSPipe *pipe = [NSPipe pipe]; 
    NSFileHandle *readh = [pipe fileHandleForReading]; 

    dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout)); 

    [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification 
                 object:readh 
                 queue:[NSOperationQueue mainQueue] 
                usingBlock:^(NSNotification *note) { 
     NSFileHandle *fileHandle = (NSFileHandle*) [note object]; 
     NSLog(@"inside listener"); 
     NSData *data = [fileHandle availableData]; 
     NSLog(@"%d", [data length]); 
     NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
     NSLog(@"%@%@", @"stdout captured:", str); 

    }]; 
    [readh waitForDataInBackgroundAndNotify]; 

    [@"Hello iOS World!" writeToFile:@"/dev/stdout" atomically:NO encoding:NSUTF8StringEncoding error:nil]; 

Le bloc de code de notification ne semble pas être appelé - la console ne émet

+1

Qu'est-ce que le programme ne après avoir écrit la chaîne? Est-ce qu'il renvoie la boucle d'exécution? –

+0

Le code est dans une méthode qui est exécutée lorsqu'un bouton d'interface utilisateur est sélectionné. Je suis gêné de dire que je ne sais pas ce qu'est une boucle de course - pouvez-vous élaborer? – Lightbeard

+2

[L'explication d'Apple sur les boucles d'exécution.] (Https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html) La boucle d'événement principale d'une application est construite au-dessus de une boucle d'exécution, donc il semble que vous êtes probablement bon à cet égard. Je l'ai soulevé parce que les documents pour '-waitForDataInBackgroundAndNotify' disent" Vous devez appeler cette méthode à partir d'un thread qui a une boucle d'exécution active. " Si vous aviez, par exemple, bloqué en attendant la notification, cela n'aurait pas fonctionné. –

Répondre

0

De Apple's documentation sur waitForDataInBackgroundAndNotify: « Vous devez appeler cette méthode à partir d'un fil qui a une boucle d'exécution actif " Cela signifie que vous ne pouvez pas appeler cela depuis un NSOperationQueue ou un NSThread. Assurez-vous donc que ce code est en cours d'exécution à partir de votre thread d'interface utilisateur principal, pas un thread d'arrière-plan.

(Publié dans le cas où quelqu'un est paresseux comme moi et ne veut pas analyser à travers les commentaires pour trouver la réponse ..)