如何轻松地在NSTextView中重定向控制台输出?

时间:2010-10-22 10:56:29

标签: objective-c cocoa redirect console nslog

假设您拥有Cocoa应用程序的代码,该应用程序通过NSlogs和printfs将自己的消息记录到Console输出中。我的目标是将所有这些输出重定向到NSView中的单独NSWindow。

如何以

的方式实现这一目标
  • 最小化要重写的代码量
  • 可以恢复
  • 最大化书面代码的重用

(通常的软件工程指南)?

3 个答案:

答案 0 :(得分:3)

  1. 程序启动后不久,使用dup(2)调用为fd 1(stdout)和2(stderr)制作重复的文件描述符。保存返回的值以供日后使用。

  2. 在FD 1和FD 2上调用close(2)。

  3. 两次调用openpty(2)。返回的第一个主设备应该是FD 1(因为它是第一个可用的FD),第二个主设备应该是2.保存两个从设备FD以便以后使用。不要担心保存name参数。现在,只要你的程序printf(2)到stdout,或者NSLogs到stderr,数据就会写入你的从FD。

  4. 现在,您必须选择想要轮询从FD或在有数据需要读取时设置信号。

  5. 对于轮询使用NSTimer。在您的计时器中,使用两个从属FD上的选择(2)来查看它们是否有数据。如果他们读取(2)它然后将其输出到您的窗口。 您还可以使两个从FD使用非阻塞IO(使用fcntl(2)到F_SETFL,从FD到O_NONBLOCK)。那么你不需要select(2),只需读取(2),如果没有什么可读的,它将返回零。

    对于信令,使用fcntl(2)到F_SETFL从属FD到O_ASYNC。然后使用signal(3)为SIGIO安装信号处理程序。调用信号处理程序时,请使用我在轮询部分描述的两种方法之一。

    如果在运行时您想要放弃所有这些更改并将所有内容恢复正常,请执行以下操作:

    1. 在FD 1和FD 2上调用close(2)。

    2. 在上面第一部分的步骤1中保存的两个FD上调用dup(2)。以正确的顺序执行dup(2),因此stdout使用FD 1,stderr使用FD 2.

    3. 现在写入stdout和stderr的任何东西都会转到原来的FD。

答案 1 :(得分:1)

如何编写自己的日志方法,通知某个控制器的日志消息(所以它可以将它放入你的(NSTextView?)视图中,然后依次调用NSLog()?

答案 2 :(得分:0)

以下是我提出的解决方案:

  1. 创建一个以NSTextView作为插座的NSWindowController(让我们称之为 A
  2. 创建一个Singleton类(让我们称之为 B )封装一个A对象,并提供一些方法,通过读取一个文件(包含所有文件)将字符串发送到A(将其附加到NSTextView)使用readInBackgroundAndNotify中的NSFileHandle来记录日志。通知后,它会调用附加方法。它还有一个启动日志记录的方法,它使用freopen(3)将某些流(stderr和stdout atm)重定向到追加模式的文件。
  3. 在项目中,只需调用B的起始日志记录方法(不需要实例化,但我猜它确实无关紧要)。
  4. 这个解决方案是考虑到Joshua Nozzi的答案和tlindner的答案而创建的,并将它们结合起来。我有和封装的解决方案,尊重问题中的三个请求(我只需要添加一行代码,我可以轻松地恢复,我也可以在其他应用程序中使用此解决方案)。我注意到有时候将NSWindowController封装成这种方式可能是错误的(而所有其他的都是由一些超级控制器管理的)。

    我最终选择了文件解决方案,因为它很容易实现,并且比tlindner的更容易使用Cocoa。此外,它还有机会在磁盘上保留一个日志文件。但当然我可能错过了一些东西,请在评论中指出我^^