代码问题 - 目标c - 等待字符串值出现在字符串值中

时间:2010-08-13 12:33:53

标签: objective-c nsstring nsdata nstask

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;

好的,这就是我的代码。它启动一个SH文件并读取输出。但是,我希望它等到“Jarvis>”在说出并打印结果之前出现在字符串中。但是,看起来像while循环,我的代码冻结在那里。没有它它会读取启动server.sh文件的正常输出,但整个过程。任何想法为什么这不起作用?

这是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

4 个答案:

答案 0 :(得分:1)

您希望将readDataToEndOfFile放入循环中。否则,它会读取数据一次,检查字符串是否存在,如果在第一次读取时没有找到它,则永远循环。

答案 1 :(得分:1)

以利亚,编辑你的代码看起来像这样:

...
[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>"];
...

循环中的此代码将连续读取文件中的输出数据并将其附加到当前输出,并在@“Jarvis>”时停止读取找到了(它会在找到@“Jarvis>”之后杀死任务,因此它不会永远运行)。

答案 2 :(得分:1)

也许尝试按照文章中发布的代码行冲洗NSPipe:

“阅读时NSTasks,NSPipes和死锁......”,

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

另一种方法可以测试NSTask& NSUnbufferedIO。

你会在Don Yacktman的书“Cocoa Programming”中找到一些示例代码。

# 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];

答案 3 :(得分:0)

对于NSTask&的非阻塞IO代码NSFileManager还可以看到DOCtor的源代码:

# 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

另请注意,如果stdout是管道而不是交互式终端(tty),许多命令行程序(内部)会将其输出缓冲到stdout。因此,无论将输出发送到管道还是tty,某些命令行程序都有特殊选项来对其输出进行行缓冲。

tcpdump -l
grep --line-buffered
...