NSlogsとprintfsを介して独自のメッセージをコンソール出力に記録するCocoaアプリのコードがあるとします。私の目標は、このすべての出力をNSViewの別のNSWindowにリダイレクトすることです。
どうすればこれを達成できますか
- 書き直すコードの量を最小限に抑えます
- 元に戻すことが可能になります
- 記述されたコードの再利用を最大化します
(通常のソフトウェアエンジニアリングガイドライン)?
NSlogsとprintfsを介して独自のメッセージをコンソール出力に記録するCocoaアプリのコードがあるとします。私の目標は、このすべての出力をNSViewの別のNSWindowにリダイレクトすることです。
どうすればこれを達成できますか
(通常のソフトウェアエンジニアリングガイドライン)?
プログラムの開始後すぐに、dup(2)呼び出しを使用して、fd 1(stdout)と2(stderr)のファイル記述子を複製します。後で使用するために戻り値を保存します。
FD1およびFD2でclose(2)を呼び出します。
openpty(2)を2回呼び出します。返される最初のマスターはFD1(最初に使用可能なFDであるため)であり、2番目のマスターは2である必要があります。2つのスレーブFDを後で使用できるように保存します。nameパラメータの保存について心配する必要はありません。これで、プログラムprintf(2)をstdoutに、またはNSLogsをstderrにすると、データがスレーブFDに書き込まれます。
ここで、スレーブFDをポーリングするか、読み取るデータがあるときに信号を設定するかを選択する必要があります。
ポーリングには、NSTimerを使用します。タイマーで、2つのスレーブFDでselect(2)を使用して、データがあるかどうかを確認します。彼らがそれを読んだら(2)、それをあなたのウィンドウに出力します。2つのスレーブFDにノンブロッキングIOを使用させることもできます(fcntl(2)を使用してスレーブFDをO_NONBLOCKにF_SETFLします)。次に、select(2)は必要ありません。単に(2)を読み取るだけで、読み取るものがない場合はゼロが返されます。
シグナリングには、fcntl(2)を使用してスレーブFDをO_ASYNCにF_SETFLします。次に、signal(3)を使用して、SIGIOのシグナルハンドラーをインストールします。シグナルハンドラが呼び出されたら、ポーリングのセクションで説明した2つの方法のいずれかを使用します。
実行時にこれらの変更をすべて破棄し、すべてを通常に戻したい場合は、次のようにします。
FD1およびFD2でclose(2)を呼び出します。
上記の最初のセクションのステップ1で保存した2つのFDでdup(2)を呼び出します。stdoutがFD1を使用し、stderrがFD 2を使用するように、dup(2)を正しい順序で実行します。
これで、stdoutとstderrに書き込まれたものはすべて、元のFDに送られます。
ログメッセージをコントローラーに通知する独自のログメソッドを作成するのはどうですか((NSTextView?)ビューに配置してから、NSLog()を順番に呼び出すことができますか?)
これが私が思いついた解決策です:
readInBackgroundAndNotify
と呼びます)を作成しNSFileHandle
ます。通知されると、appendingメソッドを呼び出します。ファイルへのログオンを開始する方法もあります。これはfreopen(3)
、一部のストリーム(stderrおよびstdout atm)を追加モードのファイルにリダイレクトするために使用します。このソリューションは、Joshua Nozziの回答とtlindnerの回答の両方を考慮して作成され、それらを組み合わせています。質問の3つのリクエストを尊重するソリューションをカプセル化しました(コードを1行追加するだけで、簡単に元に戻すことができ、他のアプリでもこのソリューションを使用できます)。NSWindowControllerをこのようにカプセル化するのは間違っている場合があることに気づきました(他のすべてのものはスーパーコントローラーによって管理されています)。
実装が非常に簡単で、tlindnerのものよりもCocoaに似ているため、最終的にファイルソリューションを選択しました。また、ディスク上に保持されるログファイルを持つ機会を提供します。しかしもちろん、私は何かを逃したかもしれません、コメントで私に指摘してください^^