2010-10-22 3 views
0

Предположим, у вас есть код приложения Cocoa, который регистрирует свои собственные сообщения через NSlog и printfs на выходе Console. Моя цель - перенаправить весь этот вывод в отдельный NSWindow в NSView.Как я могу легко перенаправить вывод консоли в NSTextView?

Как я могу добиться этого таким образом, чтобы

  • сводит к минимуму объем кода переписывать
  • позволяет вернуться
  • максимизирует повторное использование написанного кода

(обычные линии разработки программного обеспечения)?

+0

Что вы подразумеваете под "revert back"? –

+0

Чтобы вернуться к предыдущему поведению: NSLogs/printfs и т. Д. Печатаются в консоли. Простите меня за мой плохой английский – rano

ответ

0

Вот решение, которое я придумал:

  1. Создание NSWindowController, который имеет NSTextView как выход (давайте назовем это A)
  2. Создать класс Singleton (давайте назовем это B), который инкапсулирует объект A и предоставляет некоторые методы для отправки строк в A (который добавляет его в свой NSTextView) путем чтения файла (который содержит все записи) с использованием readInBackgroundAndNotify от NSFileHandle. При уведомлении он вызывает метод добавления. Он также имеет способ запуска регистрации в файл, который использует freopen(3) для перенаправления некоторого потока (stderr и stdout atm) в файл в режиме добавления.
  3. В проекте просто вызовите метод начального ведения журнала B (без необходимости создания экземпляра, но я думаю, это действительно не имеет значения) после его импорта.

Это решение было создано с учетом ответа Джошуа Ноцци и единства Тлинднера и сочетает их. У меня есть и инкапсулированное решение, которое учитывает три запроса в вопросе (я должен добавить только строку кода, я могу вернуться обратно легко, и я могу использовать это решение и в других приложениях). Я заметил, что иногда может быть неправильно, что NSWindowController инкапсулирован таким образом (тогда как все остальные управляются каким-то суперконтроллером).

Я, наконец, решил использовать файловое решение, так как он очень прост в реализации и более какаоподобный, чем у tlindner's. Также он дает возможность иметь файл журнала, который сохраняется на диске. Но, конечно, я, возможно, что-то пропустил, указать на это в комментариях, пожалуйста, ^^

+0

FILE * myStdoutFile = freopen ("myLogFile", "w", stdout) ; Это должно сработать. Но единственный способ вернуться назад - это дублировать (2) оригинальный файловый дескриптор. – tlindner

+0

На самом деле вам нужно будет сделать FILE * myStdoutFile = freopen ("myLogFile", "rw", stdout); Вы должны быть осторожны относительно положения файла. Когда что-то записывается в файл, позиция будет отмечена на конце, поэтому вы должны установить ее до чтения. – tlindner

+0

Я делаю freopen ("myLogFile", "a", stdout) – rano

1

Как насчет написания своего собственного метода журнала, который сообщает некоторый контроллер сообщения журнала (так что он может поместить его в (NSTextView?) Точка зрения, а затем вызывает NSLog(), в своей очереди?

+0

Я должен переписать большую часть кода, чтобы заменить все записи, ну а макрос мог бы облегчить эту работу. Я думаю, – rano

3
  1. Вскоре после того, как ваша программа начнет использовать вызов dup (2) для создания дубликатов дескрипторов файлов для fd 1 (stdout) и 2 (stderr). Сохраните возвращаемые значения позже.

  2. Вызов close (2) на FD 1 и FD 2 .

  3. Позвоните в openpty (2) дважды. ter, должен быть FD 1 (потому что это первый доступный FD), а второй мастер должен быть 2. Сохраните два подчиненных FD для более позднего. Не беспокойтесь о сохранении параметра имени. Теперь, когда ваша программа printf (2) на stdout или NSLogs на stderr, данные будут записаны в ваши подчиненные FD.

  4. Теперь вы должны выбрать, хотите ли вы опросить ведомые FD или настроить сигнал, когда есть данные для чтения.

Для опроса используйте NSTimer. В вашем таймере используйте select (2) на ваших двух подчиненных FD, чтобы узнать, есть ли у них данные. Если они читают (2), а затем выводят его в окно. Вы также можете получить два подчиненных FD для использования неблокирующего IO (используйте fcntl (2) для F_SETFL подчиненных FD для O_NONBLOCK). Тогда вам не нужно выбирать (2), вы просто читаете (2), и он будет возвращать ноль, если читать нечего.

Для передачи сигналов используйте fcntl (2) для F_SETFL подчиненных FD для O_ASYNC. Затем используйте сигнал (3) для установки обработчика сигналов для SIGIO. Когда вызывается обработчик сигнала, используйте один из двух методов, которые я описываю в разделе опроса.

Если во время выполнения вы хотите, чтобы отменить все эти изменения и установить все обратно в нормальное сделать это:

  1. вызов близко (2) на FD 1, FD и 2.

  2. вызова dup (2) на двух FD, сохраненных с шага 1 в первом разделе выше. Выполните DUP (2) в правильном порядке, чтобы стандартный вывод использует FD 1 и STDERR использует FD 2.

Теперь все, что написано на стандартный вывод и стандартный поток ошибок будет идти к оригинальным ФД.

+0

+1 для очень подробного ответа – rano

+0

Как насчет 'freopen (3)'? – rano

+0

freopen (3) бесполезен в отношении вашего вопроса. – tlindner

Смежные вопросы