cocoa - 解决传递大量数据时 NSFileHandle NSTask 阻塞的问题

标签 cocoa macos nstask

我有一些代码可以处理从我的应用程序导出数据。它接受一个充满 XML 的 NSString 并通过 PHP 脚本运行它来生成 HTMl、RTF 等。除非用户有一个很大的列表,否则它工作得很好。这显然是由于它超出了 NSPipe 8k 左右的缓冲区。

我在 readPipe 和 readHandle 中解决了这个问题(我认为),但我不确定如何在 writeHandle/writePipe 中处理它。应用程序将在 [writeHandle writeData:[in... 处进行沙滩球运动,除非我在 gdb 中中断它,等待几秒钟然后继续。

关于如何在我的代码中解决这个问题有什么帮助吗?

- (NSString *)outputFromExporter:(COExporter *)exporter input:(NSString *)input {
  NSString *exportedString = nil;
  NSString *path = [exporter path];
  NSTask *task = [[NSTask alloc] init];

  NSPipe *writePipe = [NSPipe pipe];
  NSFileHandle *writeHandle = [writePipe fileHandleForWriting];
  NSPipe *readPipe = [NSPipe pipe];
  NSFileHandle *readHandle = [readPipe fileHandleForReading];

  NSMutableData *outputData = [[NSMutableData alloc] init];
  NSData *readData = nil;

  // Set the launch path and I/O for the task
  [task setLaunchPath:path];
  [task setStandardInput:writePipe];
  [task setStandardOutput:readPipe];

  // Launch the exporter, it will convert the raw OPML into HTML, Plaintext, etc
  [task launch];

  // Write the raw OPML representation to the exporter's input stream
  [writeHandle writeData:[input dataUsingEncoding:NSUTF8StringEncoding]];
  [writeHandle closeFile];

  while ((readData = [readHandle availableData]) && [readData length]) {
    [outputData appendData:readData];
  }

  exportedString = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
  return exportedString;
}

最佳答案

自 10.7 起有一个新的 API,因此您可以避免使用 NSNotifications。

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 block 设置为 nil;否则,您将遇到 CPU 使用率过高的情况,因为读取永远不会停止。

[task setTerminationHandler:^(NSTask *task) {

    // do your stuff on completion

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

这都是异步的(您应该异步执行),因此您的方法应该有一个 ^completion block 。

关于cocoa - 解决传递大量数据时 NSFileHandle NSTask 阻塞的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1395273/

相关文章:

swift - 如何在 cocoa 中将pdfview更改为单页模式

iphone - 将 c-struct 放入 NSArray 的最佳方法是什么?

git - 我应该从哪里安装 git : xcode-select --install or brew install git?

cocoa - 让 NSTask 和 SMJobSubmit 正常运行的问题

cocoa - 在 QuickTime(OSX 版 Cocoa 应用程序)中打开 URL (.mp4)

cocoa - 如何设置 NSTextView 的粗体格式按钮的状态?

objective-c - 为什么 NSRegularExpression 不像 iOS 那样包含在 Mac 应用程序的 foundtion.framework 中?

macos - NS窗口 : get the current Space/Desktop of a specific window

macos - 让 java 在 Mac 终端上运行时遇到问题

swift - 当命令无法执行时 NSTask 得到通知 "command not found"