Domanda

task = [NSTask new];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObject:@"/applications/jarvis/brain/server.sh"]];
[task setCurrentDirectoryPath:@"/"];

NSPipe *outputPipe = [NSPipe pipe];
[task setStandardInput:[NSPipe pipe]];
[task setStandardOutput:outputPipe];

[task launch];

NSMutableString *outputString = [NSMutableString string];
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) {
    [outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease]];
     }

NSArray* substrings = [outputString componentsSeparatedByString:@"Jarvis>"];
NSString* finalCharlieOutputNSTask = [substrings lastObject];
NSSpeechSynthesizer * syn = [[NSSpeechSynthesizer alloc] init];
[syn startSpeakingString:finalCharlieOutputNSTask]; 
self.charlieOutput.stringValue = finalCharlieOutputNSTask;

Ok, in modo che il mio codice. Si avvia un file SH e legge l'uscita. MA, lo voglio aspettare fino a quando "Jarvis>" appare nella stringa prima di dire e stampare il risultato. Ma, sembra che con il ciclo while, il mio codice si blocca lì. Senza di essa si legge la normale uscita di lanciare il file server.sh, ma il tutto. Tutte le idee perché questo non funziona?

Questo è il file Server.sh:

echo Starting Jarvis Program D.
ALICE_HOME=.
SERVLET_LIB=lib/servlet.jar
ALICE_LIB=lib/aliceserver.jar
JS_LIB=lib/js.jar

# Set SQL_LIB to the location of your database driver.
SQL_LIB=lib/mysql_comp.jar

# These are for Jetty; you will want to change these if you are using a different http server.
 HTTP_SERVER_LIBS=lib/org.mortbay.jetty.jar

 PROGRAMD_CLASSPATH=$SERVLET_LIB:$ALICE_LIB:$JS_LIB:$SQL_LIB:$HTTP_SERVER_LIBS
 java -classpath $PROGRAMD_CLASSPATH -Xms64m -Xmx128m org.alicebot.server.net.AliceServer $1
È stato utile?

Soluzione

Elia, modificare il codice per assomigliare a questo:

...
[task launch];

NSMutableString *outputString = [NSMutableString string];
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) {
    [outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease];
}

if ([task isRunning]) {
    [task terminate];
}

NSArray *subStrings = [outputString componentsSeparatedByString:@"Jarvis>"];
...

Il codice all'interno del ciclo sarà successivamente leggere i dati in uscita dal file e aggiungerlo alla corrente di uscita, e la lettura di arresto quando @ "Jarvis>" viene trovato (sarà anche uccidere il compito dopo un @ "Jarvis>" viene trovato, in modo da non continuare a correre per sempre).

Altri suggerimenti

Si desidera mettere il readDataToEndOfFile all'interno del ciclo. In caso contrario, legge i dati una volta, i controlli per l'esistenza della stringa, poi loop per sempre se non trova in quella prima lettura.

Forse provare vampate di calore NSPipe lungo le linee di codice pubblicato in questo articolo:

"NSTasks, NSPipes e deadlock quando la lettura ...",

http://dev.notoptimal.net /2007/04/nstasks-nspipes-and-deadlocks-when.html

Un altro approccio potrebbe testare l'utilizzo di NSTask & NSUnbufferedIO.

Troverete qualche codice di esempio nel libro "Il cacao Programmazione" di Don Yacktman.

# http://www.cocoaprogramming.net
# http://www.cocoaprogramming.net/CocoaProgramming-20021010.tgz

open -e CocoaProgramming-20021010/Chapter\ 24/Animal/AnimalController.h \
        CocoaProgramming-20021010/Chapter\ 24/Animal/AnimalController.m \
        CocoaProgramming-20021010/Chapter\ 24/Calendar/CalendarController.m

# for yet another try with sample code using waitForDataInBackgroundAndNotify see:
# http://cocoawithlove.com/2009/05/invoking-other-processes-in-cocoa.html

open -e OpenFileKiller/NSTask+OneLineTasksWithOutput.m
# --> [standardOutputFile waitForDataInBackgroundAndNotify];

Per i non-blocking codice IO per NSTask & NSFileManager anche vedere il codice sorgente del medico:

# http://www.stone.com/DOCtor/
# http://www.stone.com/DOCtor/DOCtor.tar.gz

open -e DOCTor/NSFileHandle_CFRNonBlockingIO.h \
        DOCTor/NSFileHandle_CFRNonBlockingIO.m \
        DOCTor/NSFileManager-Extensions.h \
        DOCTor/NSFileManager-Extensions.m

Si noti inoltre che molti programmi a riga di comando (internamente) blocco di buffer loro allo standard output se stdout è un tubo e non un terminale interattivo (tty). Per questo motivo alcuni programmi da linea di comando hanno opzioni speciali per la linea-buffer loro produzione indipendentemente l'invio di output a un tubo o TTY.

tcpdump -l
grep --line-buffered
...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top