このサイトで何度か言われましたが、これが本当かどうかを確認したかったのです。
コード全体に NSLog 関数呼び出しを散りばめること、および Release/Distribution ビルドをビルドするときに Xcode/gcc がそれらの呼び出しを自動的に取り除くことを期待していました。
これを使用するのは避けるべきですか?もしそうなら、経験豊富なObjective-Cプログラマーの間で最も一般的な代替手段は何ですか?
このサイトで何度か言われましたが、これが本当かどうかを確認したかったのです。
コード全体に NSLog 関数呼び出しを散りばめること、および Release/Distribution ビルドをビルドするときに Xcode/gcc がそれらの呼び出しを自動的に取り除くことを期待していました。
これを使用するのは避けるべきですか?もしそうなら、経験豊富なObjective-Cプログラマーの間で最も一般的な代替手段は何ですか?
プリプロセッサマクロは確かにデバッグに最適です。NSLog()には何の問題もありませんが、より優れた機能を備えた独自のロギング関数を定義するのは簡単です。これが私が使用しているものです。ログステートメントを追跡しやすくするためにファイル名と行番号が含まれています。
#define DEBUG_MODE
#ifdef DEBUG_MODE
#define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DebugLog( s, ... )
#endif
このステートメント全体を、独自のファイルよりもプレフィックスヘッダーに配置する方が簡単であることがわかりました。必要に応じて、DebugLogを通常のObjective-Cオブジェクトと相互作用させることにより、より複雑なロギングシステムを構築できます。たとえば、独自のログファイル(またはデータベース)に書き込むログクラスを作成し、実行時に設定できる「priority」引数を含めることができるため、リリースバージョンではデバッグメッセージは表示されませんが、エラーメッセージは(これを行うと、DebugLog()、WarningLog()などを作成できます)。
ああ、#define DEBUG_MODE
アプリケーションのさまざまな場所で再利用できることを覚えておいてください。たとえば、私のアプリケーションでは、これを使用してライセンスキーのチェックを無効にし、特定の日付より前の場合にのみアプリケーションの実行を許可します。これにより、最小限の労力で、期間限定の完全に機能するベータ版を配布できます。
-prefix.pch ファイルの末尾に次の 3 行を追加します。
#ifndef DEBUG
#define NSLog(...) /* suppress NSLog when in release mode */
#endif
DEBUG
プロジェクトを作成するときにデフォルトでビルド設定で定義されるため、プロジェクトに何も定義する必要はありません。
NSLog 呼び出しは実稼働コードに残すことができますが、本当に例外的な場合、またはシステム ログに記録する必要がある情報のみに残す必要があります。
システム ログをポイ捨てするアプリケーションは煩わしく、プロらしくないと思われます。
Marc Charbonneau's answerにはコメントできないので、これを回答として投稿します。
プリコンパイル済みヘッダーにマクロを追加するだけでなく、Target ビルド構成を使用して、DEBUG_MODE
.
「デバッグ」を選択すると、アクティブな構成DEBUG_MODE
が定義され、マクロが完全NSLog
な定義に展開されます。
「リリース」アクティブ構成を選択しても定義されずDEBUG_MODE
、あなたのNSLog
ジンはリリースビルドから除外されます。
手順:
GCC_PREPROCESSOR_DEFINITIONS
)を検索します。DEBUG_MODE=1
DEBUG_MODE
が設定されていませんGCC_PREPROCESSOR_DEFINITIONS
定義で「=」文字を省略すると、プリプロセッサからエラーが発生します
また、このコメント (以下に表示) をマクロ定義の上に貼り付けて、定義がどこDEBUG_MACRO
から来たのかを思い出させてください ;)
// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
// = Debug: DEBUG_MODE=1
編集: Marc Charbonneauによって投稿され、 shoによって私の注意を引いた方法は、これよりもはるかに優れています。
デバッグモードが無効になっているときに空の関数を使用してログを無効にすることを提案した回答の部分を削除しました。自動プリプロセッサ マクロの設定を扱う部分は依然として関連性があるため、残ります。Marc Charbonneau の回答に合うように、プリプロセッサ マクロの名前も編集しました。
Xcode で自動 (および期待される) 動作を実現するには:
プロジェクト設定で、[ビルド] タブに移動し、[デバッグ] 構成を選択します。「プリプロセッサ マクロ」セクションを見つけて、という名前のマクロを追加しDEBUG_MODE
ます。
...
編集:マクロでログを有効または無効にする適切な方法については、Marc Charbonneau の回答を参照してください。DEBUG_MODE
私はマシューに同意します。本番コードでは NSLog に問題はありません。実際、ユーザーにとって便利な場合があります。そうは言っても、NSLog を使用している唯一の理由がデバッグを支援することである場合は、リリースする前にそれを削除する必要があります。
さらに、これを iPhone の質問としてタグ付けしたため、NSLog はリソースを使用しますが、これは iPhone にはほとんどありません。iPhone で何かをNSLogging している場合、アプリのプロセッサ時間が奪われます。賢く使ってください。
単純な真実は、NSLog は単純に遅いということです。
しかし、なぜ?その質問に答えるために、NSLog が何をするのか、そしてどのようにそれを行うのかを見てみましょう。
NSLog は正確に何をしますか?
NSLog は 2 つのことを行います。
ログ メッセージを Apple System Logging (asl) 機能に書き込みます。これにより、ログ メッセージが Console.app に表示されます。また、アプリケーションの stderr ストリームが端末に送信されるかどうかも確認します (アプリケーションが Xcode を介して実行されている場合など)。その場合、ログ メッセージを stderr に書き込みます (Xcode コンソールに表示されるようにします)。
STDERR への書き込みは難しくないように思えます。これは、fprintf と stderr ファイル記述子参照で実現できます。しかし、aslはどうですか?
私が見つけた ASL に関する最高のドキュメントは、Peter Hosey による 10 部構成のブログ投稿です。
あまり詳しく説明しませんが、ハイライトは (パフォーマンスに関するものであるため) 次のとおりです。
ASL 機能にログ メッセージを送信するには、基本的に ASL デーモンへのクライアント接続を開き、メッセージを送信します。BUT - 各スレッドは個別のクライアント接続を使用する必要があります。したがって、スレッド セーフにするために、NSLog が呼び出されるたびに、新しい asl クライアント接続を開き、メッセージを送信してから、接続を閉じます。
他の回答で述べたように、 #define を使用して、コンパイル時に NSLog を使用するかどうかを変更できます。
ただし、より柔軟な方法は、Cocoa Lumberjackのようなロギング ライブラリを使用することです。これにより、実行時に何かをログに記録するかどうかも変更できます。
コードで NSLog を DDLogVerbose または DDLogError などに置き換え、マクロ定義などに #import を追加し、多くの場合 applicationDidFinishLaunching メソッドでロガーをセットアップします。
NSLog と同じ効果を得るには、構成コードは次のとおりです。
[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];
セキュリティの観点からは、ログに記録される内容によって異なります。NSLog
(または他のロガー) が機密情報を書き込んでいる場合は、本番コードでロガーを削除する必要があります。
監査の観点から、監査人は、NSLog
機密情報がログに記録されていないことを確認するために、 の各使用を調べたくありません。彼/彼女は単にロガーを削除するように指示します.
私は両方のグループで働いています。私たちはコードを監査し、コーディング ガイドを作成します。私たちのガイドでは、運用コードでログ記録を無効にする必要があります。したがって、内部チームはそれを試してはいけないことを知っています ;)
また、機密情報が誤って漏洩することに伴うリスクを受け入れたくないため、本番環境にログインする外部アプリも拒否します。開発者が私たちに何を言っているかは気にしません。時間をかけて調査する価値はありません。
そして、開発者ではなく「機密」を定義することを忘れないでください ;)
また、多くのロギングを実行するアプリは、内破する準備ができているアプリであると認識しています。非常に多くのログが実行/必要とされるのには理由があり、通常は安定性がありません。ハングしたサービスを再起動する「ウォッチドッグ」スレッドがすぐそこにあります。
セキュリティ アーキテクチャ (SecArch) のレビューを一度も受けたことがない場合、これらは私たちが見ている種類のものです。
リリース コードで printf や NSLog を不必要に冗長にするべきではありません。アプリに何か問題が発生した場合、つまり回復不能なエラーが発生した場合にのみ、printf または NSLog を実行してみてください。
ロギングにはTestFlightを使用することを強くお勧めします(無料)。それらのメソッドは(マクロを使用して)NSLogをオーバーライドし、NSLogへの既存のすべての呼び出しについて、サーバー、Appleシステムログ、およびSTDERRログへのログのオン/オフを切り替えることができます。これの良い点は、テスターにデプロイされたアプリとApp Storeにデプロイされたアプリのログメッセージを、ユーザーのシステムログにログが表示されなくても確認できることです。両方の長所。