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]](または、タスクを stdout ではなく stderr に出力する必要があります)。


最終コードの提案:

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 に答える