10

这是我的代码:

task = [[NSTask alloc] init];
[task setCurrentDirectoryPath:@"/applications/jarvis/brain/"];
[task setLaunchPath:@"/applications/jarvis/brain/server.sh"];

NSPipe * out = [NSPipe pipe];
[task setStandardOutput:out];

[task launch];
[task waitUntilExit];
[task release];

NSFileHandle * read = [out fileHandleForReading];
NSData * dataRead = [read readDataToEndOfFile];
NSString * stringRead = [[[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding] autorelease];

所以我试图复制这个:

cd /applications/jarvis/brain/
./server.sh

但是在objective-c中使用NSTask。

但是,由于某种原因,当我运行此代码时,stringRead 没有返回任何内容。当我启动 .sh 文件时,它应该返回终端返回的内容。正确的?

有任何想法吗?

以利亚

4

2 回答 2

20

Xcode 错误 Xcode
中有一个错误,它会在使用标准输出的新任务启动后停止打印任何输出(它收集所有输出,但不再打印任何内容)。您将不得不调用[task setStandardInput:[NSPipe pipe]]以使其再次显示输出(或者,将任务打印到 stderr 而不是 stdout)。


最终代码建议:

NSTask *server = [NSTask new];
[server setLaunchPath:@"/bin/sh"];
[server setArguments:[NSArray arrayWithObject:@"/path/to/server.sh"]];
[server setCurrentDirectoryPath:@"/path/to/current/directory/"];

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

[server launch];
[server waitUntilExit]; // Alternatively, make it asynchronous.
[server release];

NSData *outputData = [[outputPipe fileHandleForReading] readDataToEndOfFile];
NSString *outputString = [[[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding] autorelease]; // Autorelease optional, depending on usage.
于 2010-08-12T19:52:30.570 回答
10

上面的解决方案是冻结的,因为它是同步的。调用以[server waitUntilExit]阻塞运行循环,直到任务完成。

这是获取任务输出的异步解决方案。

task.standardOutput = [NSPipe pipe];
[[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {
    NSData *data = [file availableData]; // this will read to EOF, so call only once
    NSLog(@"Task output! %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);

    // if you're collecting the whole output of a task, you may store it on a property
    [self.taskOutput appendData:data];
}];

可能你想对上面重复相同的操作task.standardError

重要的:

当您的任务终止时,您必须将 readabilityHandler 块设置为 nil;否则,您将遇到高 CPU 使用率,因为读取将永远不会停止。

[task setTerminationHandler:^(NSTask *task) {

    // do your stuff on completion

    [task.standardOutput fileHandleForReading].readabilityHandler = nil;
    [task.standardError fileHandleForReading].readabilityHandler = nil;
}];

这都是异步的(你应该异步执行),所以你的方法应该有一个 ^completion 块。

于 2013-04-29T09:06:39.273 回答