2017-11-29 14 views
2

iOS/Swiftプロジェクト全体で多くのprint()ステートメントがあります。次のようにこれらのリリースでは無視されますように、私は、グローバルオーバーライドを書いて構築します。スウィフト文字列補間性能

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { 
    #if DEBUG 
     Swift.print(items, separator: separator, terminator: terminator) 
    #endif 
} 

私は時々、例えば、高価なカスタムdebugDescriptionプロパティを持つオブジェクトを渡すprint()を呼び出す:

print("Value of myArray: \(myArray)") 

myArrayはそうのようなカスタムdebugDescriptionを実装:

var debugDescription: String { 
    get { 
     // Serialise the array for printing 
    } 
} 

私の質問があり、ます文字列をprint()またはそれ以降に渡す前に、値が計算されるのはですか?私。 #if DEBUGプリプロセッサディレクティブはリリースビルドから計算を削除しますか?

編集:私はdebugDescriptionが計算されたプロパティであることを認識しています。私はそれが呼び出されたときにはわかりません。私はそれを自分では呼んでいません。文字列補間の一部として自動的に呼び出されます。したがって、スウィフトが文字列をprint()に渡す前に補間しても、プロパティは引き続き計算されます。しかし、Swiftが代わりに "命令"を保存し、内蔵のSwift.print()ビルトインの文字列を評価するだけであれば、パフォーマンスが向上します。 したがって、この問題は、Swiftがパフォーマンスに関して文字列補間をどのように処理するかについてです。

+0

'debugDescription'は計算されたプロパティなので、' debugDescription'を呼び出すたびに生成されます。しかし、この全体がマイクロ最適化のように聞こえます –

+0

マイクロ最適化とはどういう意味ですか? – Extragorey

+0

ほとんどの場合、その文字列の生成には数ミリ秒かかります。ミリ秒が重要な場合があります。パフォーマンスについての心配 –

答えて

4

#if DEBUGプリプロセッサディレクティブは、リリースから計算を排除するには、構築していますか?

いいえ、そうではありません。 Swiftは、関数が呼び出されるとすべての関数引数を評価します。デバッガでこれを確認するか、またはdebugDescription実装にSwift.printへの呼び出しを追加することで確認できます。ターミナルで、その後

// test.swift 
struct A: CustomDebugStringConvertible { 
    let value: Int 

    var debugDescription: String { 
     Swift.print("Calling debugDescription") 
     return "A: \(value)" 
    } 
} 

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { 
    #if DEBUG 
     Swift.print(items, separator: separator, terminator: terminator) 
    #endif 
} 

let a = A(value: 42) 
print("Value of a: \(a)") 

:たとえば、これらのコンテンツのファイルを作成します。あなたが見ることができるように

> swift test.swift 
Calling debugDescription 

"Calling debugDescription"が印刷されます(つまり、debugDescriptionは評価されます)あなたのprint関数はdoesnのにもかかわらず、何もしない。今度は、DEBUGフラグを設定しましょう:

> swift -D DEBUG test.swift 
Calling debugDescription 
["Value of a: A: 42"] 

(例えばassertなど)スウィフト標準ライブラリで同様の機能が、そのパラメータのうちの1つまたは複数のautoclosuresを使用する理由です。 @autoclosure属性は、関数の引数をクロージャ内にラップします。このようにして、呼び出される関数は、(関数を呼び出すことによって)式を評価するかどうか、いつ評価するかを決めることができます。これは、呼び出し元に対して完全に透過的です。

残念ながら、@autoclosureは可変パラメータ(Any...など)で動作しないため、Swift 4.0に正確に必要なものを再現する方法はないと思います。しかし、あなたは、単一のAny引数を取るprint機能と一緒に暮らすことができる場合、あなたはこのようなあなたの関数を定義することができます:あなたはitem()を呼び出すまで今

func print(_ item: @autoclosure() -> Any, separator: String = " ", terminator: String = "\n") { 
    #if DEBUG 
     Swift.print(item(), separator: separator, terminator: terminator) 
    #endif 
} 

、機能にのみ発生しており、その最初の引数を評価しません。 #if DEBUGブロック内にあるため、リリースビルドにオーバーヘッドはありません。

-1

前処理では、リリースコードに#if DEBUGのコードは含まれません。だから、それがプロパティを計算していますから、worrryしていない、リリースコードの最適化には効果