【问题标题】:What is the best way to redirect stdout to NSTextView in Cocoa?将标准输出重定向到 Cocoa 中的 NSTextView 的最佳方法是什么?
【发布时间】:2011-01-25 06:14:08
【问题描述】:

嗨:我想将标准输出重定向到 NSTextView。这也适用于子流程的输出吗?实现这一目标的最佳方法是什么?

编辑: 根据 Peter Hosey 的回答,我实施了以下操作。但我没有收到通知。我做错了什么?

NSPipe *pipe = [NSPipe pipe];
NSFileHandle *pipeHandle = [pipe fileHandleForWriting];
dup2(STDOUT_FILENO, [pipeHandle fileDescriptor]);
NSFileHandle *fileHandle = [[NSFileHandle alloc] initWithFileDescriptor:pipeHandle];
[fileHandle acceptConnectionInBackgroundAndNotify];

NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:@selector(handleNotification:) name:NSFileHandleConnectionAcceptedNotification object:fileHandle];

【问题讨论】:

  • 这与python有什么关系?
  • @Eimantas:你说得对,这与问题没有直接关系。实际上,我正在使用 PyObj 与写入要显示的 stdout 的 Python 代码进行通信。我应该删除标签...

标签: cocoa subprocess stdout


【解决方案1】:

对于 iOS,使用 stderr 而不是 stdout。

NSPipe *pipe = [NSPipe pipe];
pipeHandle = [pipe fileHandleForReading];
dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stderr));

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNotification:) name: NSFileHandleReadCompletionNotification object: pipeHandle] ;
[pipeHandle readInBackgroundAndNotify] ;

-(void)handleNotification:(NSNotification *)notification{

    [pipeHandle readInBackgroundAndNotify] ;
    NSString *str = [[NSString alloc] initWithData: [[notification userInfo] objectForKey: NSFileHandleNotificationDataItem] encoding: NSASCIIStringEncoding] ;

}

【讨论】:

    【解决方案2】:

    看看PseudoTTY.app

    【讨论】:

      【解决方案3】:

      我也想做同样的事情,结果发现了这篇文章。在阅读了这个和 Apple 的文档后,我能够弄清楚。我在这里包括我的解决方案。在接口中声明了“pipe”和“pipeReadHandle”。在 init 方法中,我包含了以下代码:

      pipe = [NSPipe pipe] ;
      pipeReadHandle = [pipe fileHandleForReading] ;
      dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout)) ;
      
      [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNotification:) name: NSFileHandleReadCompletionNotification object: pipeReadHandle] ;
      [pipeReadHandle readInBackgroundAndNotify] ;
      

      handleNotification: 方法是

      [pipeReadHandle readInBackgroundAndNotify] ;
      NSString *str = [[NSString alloc] initWithData: [[notification userInfo] objectForKey: NSFileHandleNotificationDataItem] encoding: NSASCIIStringEncoding] ;
      // Do whatever you want with str 
      

      【讨论】:

      • 这对我帮助很大。谢谢!我使用了您的建议并添加了这两条消息,以使用以下命令使 textView 增长和自动滚动:[myTextView setText:[myTextView.text stringByAppendingString:str]]; [myTextView scrollRangeToVisible:NSMakeRange([myTextView.text length], 0)];
      • 成功的dup2后面应该跟[[pipe fileHandleForWriting] closeFile];进行清理
      【解决方案4】:

      我想将标准输出重定向到 NSTextView。

      您自己的标准输出?

      这是否也适用于子流程的输出?

      当然。

      实现这一目标的最佳方法是什么?

      文件描述符是你的朋友。

      创建一个管道(使用 NSPipe 或 pipe(2))并将 dup2 其写入端写入 STDOUT_FILENO。调用子流程时,不要设置它们的标准输出;他们将继承您的标准输出,这是您的管道。 (不过,您可能希望在子进程中关闭读取端。我不确定这是否有必要;尝试一下并找出答案。如果确实如此,您将需要使用 forkexec,并在其间关闭读取端。)

      在后台异步读取管道的读取端,使用kevent 或NSFileHandle。当新数据进入时,使用某种编码对其进行解释并将其附加到文本视图的内容中。

      如果文本视图在滚动视图中,您应该在添加之前检查滚动位置。如果它位于末尾,您可能希望在追加后将其跳回末尾。

      【讨论】:

      • 我用非工作实现编辑了问题?有什么线索吗?
      • Snej:你对dup2 的论点是错误的。然后你传递一个 NSFileHandle 指针作为文件描述符来创建一个 NSFileHandle。然后你假装写端是一个套接字并尝试接受一个连接,即使两个 FD 都没有从 listen(2) 返回(因为它们是管道,而不是套接字)。修复dup2调用,不要假装文件句柄指针是文件描述符,不要尝试为两端创建另一个文件句柄,并尝试从读取阅读结束.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-26
      • 2020-07-18
      • 2012-08-15
      • 1970-01-01
      相关资源
      最近更新 更多