ここおよびインターウェブに関する他の回答は非常に優れていますが、このちょっとした情報も言及する必要があると思います。
素晴らしい点dispatch_once
は、それがどれほど最適化されたかということでした。基本的に、最初の実行後にほとんど理解できない方法でコードを修正しましたが、(実際の) グローバル トークンを設定してチェックするよりもはるかに高速であると合理的に確信しています。
トークンは Swift で合理的に実装できますが、さらに別の格納されたブール値を宣言する必要があるのはそれほど素晴らしいことではありません。スレッドセーフではないことは言うまでもありません。ドキュメントにあるように、「遅延初期化されたグローバル」を使用する必要があります。ええ、しかし、なぜグローバル スコープをごちゃごちゃにしていますか?
誰かがより良い方法を私に納得させるまで、次のように、使用するスコープ内、またはそれにかなり近いスコープ内で do-once クロージャーを宣言する傾向があります。
private lazy var foo: Void = {
// Do this once
}()
foo
基本的には、「これを読んだとき、このブロックを実行した結果になるはずだ」と言っています。let
これは、グローバル定数とまったく同じように、適切な範囲で動作します。そしてきれい。次に、他の方法では決して使用されないものに読み込んで、好きな場所で呼び出します。そういう意味ではSwiftが好き_
です。そのようです:
_ = foo
この本当にクールな癖は、実際にはしばらく前から存在していましたが、あまり愛されていません. Void
基本的に、何かがその結果を見たいと思うまで、呼び出されていないクロージャーとして、実行時に変数をそのままにしておきます。読み取り時に、クロージャを呼び出して破棄し、その結果を に保持しfoo
ます。Void
メモリに関しては実質的に何も使用しないため、後続の読み取り (つまり_ = foo
) は CPU で何もしません。(それについて私を引用しないでください。誰かが確実にアセンブリをチェックしてください!) 好きなだけ持っていれば、Swift は基本的に最初の実行後にそれを気にするのをやめます! その古いdispatch_once_t
.
私の1つの問題はfoo
、最初の読み取りの前に別のものに設定でき、コードが呼び出されないことです! したがって、それを防ぐグローバルlet
定数です。つまり、クラス スコープ内の定数は でうまく機能しないself
ため、インスタンス変数をいじることはできません...しかし、真剣に、とにかくいつ何かを設定しVoid
ますか??
それと、戻り値の型をVoid
orとして指定する必要があります。誰だ?()
self
そしてlazy
、変数をできるだけ遅延させるだけなので、Swift はそれを on で直接実行しませんinit()
。
あなたがそれに書いていないことを覚えている限り、かなりおしゃれです!:P