アプリケーションをリリースする前にNSLogを無効にする必要がありますか?


117

iPhone用アプリをリリースするとき、無効にすると NSLog();するとパフォーマンスが向上しますか?


1
現在のプロジェクトではUALoggerを使用しています。これは、生産にログインしていない、あなたが明示的にそれを聞いていない場合は、。また、すぐに使える重大度レベル(デバッグ情報など)のようなプレーンなNSLogに比べて他の利点があります。よくやった!
アントンGaenko 2014

1
「パフォーマンスは向上しますか?」に関する質問に回答するには はい、ありますが、得られる収量はNSLog()アプリ全体の数に依存します。NSLog()実行に時間がかかり、アプリのランタイムにオーバーヘッドが追加されます。とにかく、単純なDEBUGプリプロセッサマクロでパフォーマンスが向上する場合は、無効にする必要があります。
スコット

また、コードにNSLog / printステートメントがたくさんある場合は、デバッガについてさらに学習することをお勧めします。興味のある情報を出力するブレークポイントを定期的に設定し、自動的に続行します。はい、それは実行を少し遅くすることができますが、ほとんどの場合それは圧倒的ではありません。また、条件付きブレークにより、予期しない事態が発生したときに調査できます。
bshirley

回答:


127

これを行う1つの方法は、ビルド設定に移動し、デバッグ構成の下で、「プリプロセッサマクロ」の値に次のような値を追加することです。

DEBUG_MODE=1

これは、デバッグ構成でのみ行い、ベータ版またはリリース版では行わないでください。次に、一般的なヘッダーファイルで次のようなことができます。

#ifdef DEBUG_MODE
#define DLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DLog( s, ... ) 
#endif

どこでもNSLog 使用する代わりにDLog。テストとデバッグを行うと、デバッグメッセージが表示されます。ベータ版または最終リリースをリリースする準備ができると、これらのDLog行はすべて自動的に空になり、何も出力されません。この方法では、変数の手動設定やNSLogs必須のコメントはありません。ビルドターゲットを選択すると、それが処理されます。


Xcode 4.5では、「関数 'DLog'の暗黙の宣言はC99では無効です」という警告が表示されるため、この機能は機能しません。
セルゲイグリシオフ2013年

2
@SergiusGee:関数の宣言が見つからない場合、暗黙の宣言警告が表示されます。その場合、宣言しようとしていると見なされます。これが宣言されているヘッダーファイルにクラスがアクセスできることを確認してください。
sudo rm -rf 2013年

1
ユーザーからより適切なエラーレポートを受け取ることができないため、ログアウトしないでください。非同期のロギングとlogLevelsを使用して、パフォーマンスヒットをほぼゼロに制限します!(cocoa
lumberjack

2
#ifdefではなく#ifを使用します。これは、DEBUG_MODE 0がまだ真のパスを通過するためです
Grady Player

1
これは質問の答えにはなりません
Martin Mlostek 2017年

117

Xcode 5およびiOS 7のアップデート

注:リリースビルドでprint()ステートメントを削除するXcode 7 / Swift 2.1ソリューションについては、ここで私の答えを見つけてください

はい、コードを遅くするだけで、リリースバージョンでは何の役にも立たないので、リリースコードからNSLogステートメントを削除する必要があります。幸い、Xcode 5(iOS 7)では、リリースビルドですべてのNSLogステートメントを「自動的に」削除するのは驚くほど簡単です。だからそれをしないのはなぜですか。

最初に行う3つのステップ、次にいくつかの説明

1)Xcodeプロジェクトで、「yourProjectName-prefix.pch」ファイルを見つけます(通常、これはmain.mファイルが置かれている「サポートファイル」グループの下にあります)

2)「.pch」ファイルの最後に次の3行を追加します。

#ifndef DEBUG
   #define NSLog(...);
#endif

3)「デバッグ」バージョンと「リリース」バージョンの違いをテストします。これを行う1つの方法は、「スキームの編集」->「アプリ名の実行」->「情報」タブの下で、デバッグとリリースの間のドロップダウンボックスを使用して選択することです。リリースバージョンでは、デバッグコンソールにNSLog出力は表示されません。

これはどのように機能しますか?

まず、プリプロセッサは比較的「ダム」であり、コンパイラが呼び出される前に「テキストの置き換え」として機能することを知っておく必要があります。これは、「#define」を#defineステートメントに続くものに置き換えます。

#define NSLog(...);

(...)括弧の間の「何でも」()の略です。;最後に心も。コンパイラーがこれを最適化するため、これは厳密には必要ありませんが、より「正しい」ため、ここに配置するのが好きです。私たちの後#defineプリプロセッサは「何もない」と交換します、そしてそれはただで始まる、完全なラインを捨てますので、「何も」ありませんNSLog...までを含みます;

定義ステートメントは#ifdef#ifndef(定義されている場合)または(定義されていない場合)を使用して条件付きにすることができます。

ここではと記述します#ifndef DEBUG。これは、「シンボルDEBUGが定義されていない場合」を意味します。#ifdefまたは#ifndefで「閉じた」ことの必要性#endif

Xcode 5は、ビルドモードが「DEBUG」の場合、デフォルトで「DEBUG」シンボルを定義します。「リリース」では、これは定義されていません。これはプロジェクト設定の[ビルド設定]タブで確認できます-> [Apple LLVM 5.0-前処理]-> [プリプロセッサマクロ]セクションまでスクロールします。シンボル「DEBUG」がリリースビルドに対して定義されていないことがわかります。

最後に、.pchファイルはXcodeによって自動的に作成され、コンパイル時にすべてのソースファイルに自動的に含まれます。つまり、すべてを#defineソースファイルのそれぞれに挿入するようなものです。


1
@Whasssaaahhh、ありがとうございます。ログステートメントにコードを配置しないように注意してください。プリプロセッサは、内部にあるものを無視してステートメント全体を削除NSLogます。
エリックプラトン2014年

1
プリプロセスまたはマクロにデバッグフラグが設定されていない古いプロジェクトの場合、ターゲットではなくプロジェクトの「debug = 1」を追加することが重要です
Priebe

1
また、NSLog何もしないステートメントとして使用しないでください。たとえば、中括弧でif(AllCool) NSLog(@"Cool!Do Nothing!"); else...ポップしNSLogますif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
アーカディボブ

33

上記のほとんどすべての回答が解決策を提案していますが、問題を説明していません。グーグルで検索して、その理由を見つけました。これが私の答えです:

はい、リリースバージョンでNSLogをコメントアウトすると、パフォーマンスが向上します。NSLogはかなり遅いからです。どうして?NSLogは2つのことを行います。1)Apple System Logging(ASL)にログメッセージを書き込みます。2)アプリがxcodeで実行されている場合、stderrにも書き込みます。

主な問題は最初の問題にあります。スレッドセーフを実現するために、NSLogが呼び出されるたびに、ASL機能への接続が開かれます。メッセージを送信し、接続を閉じます。接続操作は非常に高価です。別の理由は、NSLogがログに記録するためのタイムスタンプを取得するためにある程度の時間を費やしていることです。

ここからの参照


23

私の個人的なお気に入りは、可変個のマクロを使用することです。

#ifdef NDEBUG
    #define NSLog(...) /* suppress NSLog when in release mode */
#endif

1
これはどこに置くの?
user6631314

20

呼びかけないことを賢明にコメントしたすべての人々に加えて NSLog()本番行わ加えて、私はそれを追加します:

これらのNSLog()出力文字列はすべて、ストアからアプリをダウンロードし、Xcodeを実行しているMacに接続されたデバイスでアプリを実行するすべてのユーザーに表示されます([オーガナイザー]ウィンドウから)ます。

ログに記録する情報に応じて(特に、アプリがサーバーに接続する場合、認証を行う場合など)、これは深刻なセキュリティ問題になる可能性があります。


情報をありがとう-これはドキュメントのどこかにありますか、それとも自分で見つけたのですか?Swiftの印刷については、まだ正しいですか?
Ronny Webers、2015

ドキュメントを読んだ覚えがない。アーカイブしたビルド(ストアに送信したものと同じバイナリ)をデバイスにインストールし、Xcodeに接続しました。Swiftと同じかどうかはわかりませんprint()が、おそらく同じです。
Nicolas Miari

@NicolasMiari Xcodeに接続するとはどういう意味ですか?どのようにしてバイナリをXcodeにプラグインできるか、実際に同じことを試してみたいと思います。だから提案してください。ありがとう。
iDevAmit 2016年

@iDeveloperつまり、AppStoreからデバイス(iPhoneなど)にアプリをダウンロードし、そのデバイスをUSB経由でXcodeに接続し、アプリを起動して、Xcodeの[デバイス]ウィンドウでログを確認します。
Nicolas Miari、2016年

3
@Whasssaaahhhの出力がデバイスコンソールに出力されません。テストしたところです
Anish Parajuli웃2016年

13

プロジェクトのデフォルト設定

Xcodeのプロジェクトの現在のデフォルト設定内では、NS_BLOCK_ASSERTIONSマクロはリリースバージョンとDEBUG=1デバッグバージョンで1に設定されます。

なので、次の方法がいいです。

// NS_BLOCK_ASSERTIONS is defined by default, as shown in the screenshot above.
// Or, you can define yourself Flags in the `Other C Flags` -> `Release`.
#ifndef NS_BLOCK_ASSERTIONS
    #define _DEBUG
#endif

#ifdef _DEBUG
// for debug mode 
#define DLog(fmt,...) NSLog(@"%s " fmt, __FUNCTION, ##__VA_ARGS__) 
... /// something extra
#else
// for release mode
#define DLog(fmt,...) /* throw it away */
... /// something extra
#endif

5

はい、無効にする必要があります。特に、コードの速度を最大化しようとしている場合。NSLoggingは、他の開発者が調べようとしている可能性のあるシステムログを左右に汚染し、速度が重要なコード(ループ内など)に大きな影響を与える可能性があります。 「速度が30%向上した」アップデートをリリースしました。数週間後... ;-)


5

すべての良い回答ですが、主にアプリの開発/テスト段階で使用することを検討できるもう1つの小さなトリックがあります。

また、コードを直接制御できない問題を示す可能性のあるメッセージではなく、デバッグコードをオフにするだけの場合は、アプリのリリースコードにも役立ちます。

トリック:

.mファイルの先頭に次の行を含めるだけで、.mファイルごとにNSLogをオフにできます

#define NSLog(...)

注:DO NOT、唯一の.mファイルを、この.Hファイルを入れて!

これは、NSLog()代わりにプリプロセッサーマクロを展開してコンパイラーを評価させるだけです。マクロは引数を取り除くだけです。

もう一度オンにしたい場合は、いつでも使用できます

#undef NSLog

たとえば、次のようなことを行うことで、特定のメソッドグループを中心としたNSLogの呼び出しを防ぐことができます。

#define NSLog(...)
-(void) myProblematicMethodThatSometimesNeedsDebugging {
    ...
}
#undef NSLog

3

NSLogは遅いため、リリースビルドには使用しないでください。以下のような単純なマクロは、無効にする必要のあるアサートとともに無効にします。NSLogをリリースビルドで必要とするあまり一般的ではないケースでは、直接呼び出すだけです。「その他のcフラグ」のビルド設定に「-DNDEBUG」を追加することを忘れないでください。

#ifdef NDEBUG
#define MYLog(f, ...) 
#else
#define MYLog(f, ...) NSLog(f, ## __VA_ARGS__)
#endif


0

これはどうですか?

#ifndef DEBUG_MODE
        fclose(stderr);     // the simplest way to disable output from NSLog
#endif    

1
これは出力を無効にしますが、処理時間を節約しません。つまり、NSLogは引き続き呼び出され、その引数が解析されます
dwery

0
var showDebugLogs = false;

    func DLog(format: String, args: CVarArgType...) {
        if showDebugLogs{
        println(String(format: format, arguments: args))
        }
    }

これは、追加の引数も受け入れます。必要に応じて、showDebugLogsパラメータ値をtrueまたはfalseに設定するだけです。


これはすばらしいことですが、すべての呼び出しオーバーヘッドと、Dlog関数に渡される引数を計算することによるオーバーヘッド(および潜在的な副作用)の問題が依然としてあります。
トッドリーマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.