我正在尝试使用NSTask运行一个简单的bash脚本并将输出定向到文本视图.执行任务后,我的应用程序的CPU使用率为100%,即使它很简单echo(暂时).
我创建了一个全新的项目来隔离问题:
@interface AppDelegate ()
@property (nonatomic) NSTask *task;
@property (nonatomic) NSPipe *pipe;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self.pipe = [NSPipe pipe];
self.pipe.fileHandleForReading.readabilityHandler = ^(NSFileHandle *h) {
NSLog(@"Read: %@", [h readDataToEndOfFile]);
};
self.task = [[NSTask alloc] init];
self.task.launchPath = @"/bin/bash";
self.task.arguments = @[@"-c", @"echo test"];
self.task.standardOutput = self.pipe;
[self.task launch];
}
@end
Run Code Online (Sandbox Code Playgroud)
它被正确执行并输出(作为NSData)记录NSLog:
PipeTest[3933:2623] Read: <74657374 0a>
Run Code Online (Sandbox Code Playgroud)
但是,在我终止我的应用程序之前,CPU使用率保持在100%.
编辑:
Time Profiler测试返回下面的列表,但我不知道如何解释这个.

我正在编写一个Cocoa应用程序,它需要执行一个UNIX程序并逐行读取它的输出.我设置了NSTask和NSPipe:
task = [[NSTask alloc] init];
pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
//... later ...
[task setArguments:...];
[task setLaunchPath:@"..."];
[task launch];
handle = [[task fileHandleForReading] retain];
Run Code Online (Sandbox Code Playgroud)
该命令不会终止,直到程序通知它为止[task terminate].我试图从手柄读取几种方法,如-readInBackgroundAndNotify,while([(data = [handle availableData]) length] > 0)和-waitForDataInBackgroundAndNotify,但管道似乎从来没有得到任何数据.有什么方法可以"戳" NSTask或NSPipe通过刷新数据?
编辑:用-readInBackgroundAndNotify:
[handle readInBackgroundAndNotify];
notification_block_t handlerBlock =
^(NSNotification *notification) {
NSData *data = [[notification userInfo]
objectForKey: NSFileHandleNotificationDataItem];
/*... do stuff ...*/
[self addNotification: handle block: handlerBlock];
};
[self addNotification: handler block: handlerBlock]; …Run Code Online (Sandbox Code Playgroud) 我需要使用NSPipe通道实现两个线程之间的通信,问题是我不需要通过指定此方法来调用terminal命令.
[task setCurrentDirectoryPath:@"....."];
[task setArguments:];
Run Code Online (Sandbox Code Playgroud)
我只需要写一些数据
NSString * message = @"Hello World";
[stdinHandle writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
Run Code Online (Sandbox Code Playgroud)
并在另一个线程上接收此消息
NSData *stdOutData = [reader availableData];
NSString * message = [NSString stringWithUTF8String:[stdOutData bytes]]; //My Hello World
Run Code Online (Sandbox Code Playgroud)
例如,使用NamedPipeClientStream,NamedPipeServerStream类可以轻松完成c#中的这些操作,其中管道由id字符串注册.
如何在Objective-C中实现它?
我试图从swift中调出枪支来制作一些情节.png.但是,下面的程序不起作用 - 生成的1.png文件为空.如果我离开"set term aqua",它会调用aqua窗口中的情节.但是,当我尝试将输出设置为file(png或pdf)时,结果始终为空文件.
gnuplot命令没问题---我可以正确地手动运行它们.
import Foundation
let task = NSTask()
task.launchPath = "/opt/local/bin/gnuplot"
task.currentDirectoryPath = "~"
let pipeIn = NSPipe()
task.standardInput = pipeIn
task.launch()
let plotCommand: NSString =
"set term png\n" +
"set output \"1.png\"\n"
"plot sin(x)\n" +
"q\n"
pipeIn.fileHandleForWriting.writeData(plotCommand.dataUsingEncoding(NSUTF8StringEncoding)!)
Run Code Online (Sandbox Code Playgroud)
我是快速和管道的新手,所以请告诉我是否有错误或不推荐的代码.
我正在通过NSTask. 这些工具可能会运行几秒钟,并不断地将文本输出到stdout. 最终,该工具将自行终止。我的应用程序使用readInBackgroundAndNotify.
如果我在工具退出后立即停止处理异步输出,我通常会丢失一些当时尚未交付的输出。
这意味着我必须等待更长的时间,以允许 RunLoop 处理挂起的读取通知。我如何知道我何时阅读了该工具写入管道的所有内容?
这个问题可以在下面的代码中通过删除带有runMode:调用的行来验证- 然后程序将打印零行已处理。所以看起来在进程退出时,队列中已经有一个等待传递的通知,并且传递是通过runMode:调用发生的。
现在,看起来在工具退出后简单地调用runMode: 一次可能就足够了,但我的测试表明它不是 - 有时(具有大量输出数据),这仍然只会处理剩余数据的一部分。
注意:诸如使调用的工具输出某些文本结束标记之类的变通方法不是我寻求的解决方案。我相信必须有一些适当的方法来做到这一点,从而以某种方式发出管道流的结束信号,这就是我在答案中寻找的。
下面的代码可以粘贴到一个新的 Xcode 项目AppDelegate.m文件中。
运行时,它调用一个工具来生成一些更长的输出,然后等待工具终止waitUntilExit。如果它随后立即删除outputFileHandleReadCompletionObserver,则将错过该工具的大部分输出。通过添加runMode:持续一秒的调用,接收工具的所有输出——当然,这个定时循环不是最佳的。
而且我想保持runModal函数同步,即它在收到工具的所有输出之前不会返回。它确实在我的实际程序中以自己的方式运行,如果这很重要(我看到 Peter Hosey 的评论警告waitUntilExit会阻止 UI,但在我的情况下这不是问题)。
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[self runTool];
}
- (void)runTool
{
// Retrieve 200 lines of text by invoking `head -n 200 /usr/share/dict/words`
NSTask *theTask = [[NSTask alloc] init];
theTask.qualityOfService …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用Pipe's fileHandleForReading' readabilityHandler来读取a standardOutput和standardErrora Process.然而,terminationHandler被调用的那一刻实际上是在我readabilityHandler第一次被召唤的那一刻之前.
我不确定为什么这个过程会这样做,但这意味着我没有获得所有数据,因为我假设进程终止意味着所有输出都被刷新到管道.既然不是这样,有没有办法告诉我什么时候没有更多的输出要读?我假设涉及检查a FileHandle是否仍处于打开状态,但我没有看到API.
以下是我的代码的基本概念示例:
let stdOutPipe = Pipe()
let stdErrPipe = Pipe()
stdOutPipe.fileHandleForReading.readabilityHandler = { stdOutFileHandle in
let stdOutPartialData = stdOutFileHandle.readDataToEndOfFile()
guard !stdOutPartialData.isEmpty else {
print("Time to read, but nothing to be read?") // happens a lot
return
}
self.tempStdOutStorage.append(stdOutPartialData)
}
stdErrPipe.fileHandleForReading.readabilityHandler = { stdErrFileHandle in
let stdErrPartialData = stdErrFileHandle.readDataToEndOfFile()
guard !stdErrPartialData.isEmpty else {
print("Time to read, …Run Code Online (Sandbox Code Playgroud) 我想使用NSTask模拟终端运行命令.代码如下.它可以在循环中获得输入并返回过程输出.
int main(int argc, const char * argv[])
{
@autoreleasepool {
while (1) {
char str[80] = {0};
scanf("%s", str);
NSString *cmdstr = [NSString stringWithUTF8String:str];
NSTask *task = [NSTask new];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObjects:@"-c", cmdstr, nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", string);
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:当循环结束时,运行环境恢复到初始化状态.例如,默认运行路径是/Users/apple,我运行cd /以更改路径/,然后运行pwd,它返回/Users/apple而不是/.
那么如何才能 …
我有一个 NSTask 处理从标准输入传递的参数。参数通过NSFileHandle.
它工作正常,但我们的命令行工具从 stdin 读取输入,直到它收到 EOF 符号(按 Ctrl+C)。
我不认为我可以将 EOF 符号添加到 ASCII 字符串中,那么有哪些选项呢?任何反馈表示赞赏!
提前致谢!
我目前正在开发一个应用程序,该应用程序从 OS X 应用程序中的文本字段收集信息,然后访问 openssl 二进制文件以根据这些文本字段生成 CSR 和私钥。这是当前的代码
let keySizeValue = keySizes[keySizeChoice.indexOfSelectedItem]
mainTask.launchPath = "/usr/bin/openssl"
mainTask.arguments = ["req", "-new", "-newkey", "\(keySizeValue)", "-passout", "pass:\(privateKeyPassword.stringValue)","-keyout", "/Users/\(userName)/Desktop/Certs/\(privateKeyText.stringValue).key", "-subj" ,"\"/C=US/ST=\(stateText.stringValue)/L=\(cityText.stringValue)/O=\(organizationText.stringValue)/OU=\(departmentText.stringValue)/CN=\(commonNameText.stringValue)\"", "-out", "/Users/\(userName)/Desktop/Certs/MyNew.csr"]
let pipe = NSPipe()
mainTask.standardInput = pipe
mainTask.launch()
mainTask.waitUntilExit()
mainTask.terminate()
Run Code Online (Sandbox Code Playgroud)
但是我收到一个错误,指出Subject does not start with '/'. 希望有人能向我提出某种想法,解释为什么它说我的主题不是以 / 开头,尽管它显然是这样。
谢谢大家