Initialization Closure って何だ?

iOS, Swift

この記事は最終更新日から1年以上が経過しています。

19新卒の永田です。10月の配属以降、iOSアプリの開発に取り組んでいます。
今回はタイトルの通り、Initialization Closureについてまとめようと思います。

TL; DR

  • Initialization Closureは Stored Property の初期化に使われる書き方。
  • Computed Propertyではないので、 {}の中は 1度しか呼ばれない

未知との遭遇

現在開発中のアプリでUIViewControllerのライフサイクルとAuto Layoutの反映タイミングに悩まされ、
viewDidLayoutSubview()で最初の一回だけ処理をしたくなり、この記事にたどり着きました。

実際に以下のようなコードを書けば問題は解決したのですが、何がどうなっているのか・なぜ上手くいってるのかがわかりませんでした。

何がわからんのか

当時わからなかったことをまとめるとこんな感じだったと思います。

  • 見た目Computed Propertyと似てるけど何が違うのか
  • 何故これで initCollectionViewFlowLayoutの中身が一度しか呼ばれないのか
  • {}の後の ()は何者なのか

最近ようやくこの謎が解けた(っぽい)ので、これらの点について話をします。

Computed Propertyとの違い

変数名の後に { return }みたいなのがあるのでComputed Propertyと混同してしまったのですが、
この initCollectionViewFlowLayoutはInitialization Closureという書き方で
Stored Propertyとして定義されているみたいです( =があるのでそれもそうか…という感じ)。

Initialization Closureとは

Stored Propertyの初期化の際に、初期値としてクロージャの実行結果を渡す書き方のことです。

例1 ) 要素数50のフィボナッチ数列 (Stored Property)

上の例では、フィボナッチ数列の初期化を行うクロージャの返り値を
定数 fibonacciに渡しています( return temporaryArray)。
{}の中で初期化の処理をクロージャとして定義して、最後に ()をつけることで
そのクロージャを即実行して [Int]の値を取得しているという感じです。
最後の ()を付けないと、 fibonacciにクロージャ(この場合 () -> [Int]のクロージャ)を代入する形になってしまい、コンパイルエラーが起きます。

何故処理が一度しか呼ばれないのか

答えはシンプルで、 initCollectionViewFlowLayoutStored Propertyだから です。
Computed Propertyは値を保持しないので参照するたびに {}の中の計算が走ります(例2)が、
Stored Propertyの場合は値を保持するので、参照しても {}内の計算は行われず、初期化の時に {}内で returnされた値を使うだけになります(例3)。

例2 ) 要素数50のフィボナッチ数列 (Computed Property)

例3 ) Initialization Closureが1度しか呼ばれていないことの確認

まとめ

ここまでの内容をまとめると、今回の initCollectionViewFlowLayoutは、Initialization Closureの正規の使い方というよりかは、その仕組みを応用した手法なのかな?と感じました。これ思いついた人賢いな〜〜とシンプルに感心。

ここまで理解するのにかなり時間がかかってしまいましたが、また便利そうな手法を1つ知ることができたのでこれから上手く使っていこうと思います。

参考

iOS, Swift