Codice problema - Obiettivo C - in attesa di valore stringa ad apparire in valore stringa
-
28-09-2019 - |
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
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
...