クロージャについてまとめたものを共有します。
環境は以下の通りです
Swift 5.1
Xcode 11.3
クロージャの形態
{(パラメータリスト) → リターン型 in
実行するコード}
何もパラメーターで受け取らず、何も返さないクローザーは ( ) → ( )
です。
Swiftの関数はクロージャ!
Swiftの関数はクロージャです。
クロージャは「関数の本体内のスコープ内で外部変数への参照をキャプチャできること」を意味します。
例えば、下のドグのインスタンスを参照してみよう。
whatThisDogSays
を参照できるのが分かります。
dothis
関数にはDog
インスタンスがないが参照により"arf"
を呼び出します。
Dog 変数 d
と関数 barkFunction
の両方が、同じDog
インスタンスへの参照を保持しているからです。
クロージャがコードをどのように改善するか
作ったクロージャコードを簡略化にして、より便利に使うことができます。
上の関数はイメージを作るtrailing closureです。
繰り返されるコーディングが嫌ならこのように書き換えます。
ハードコーディングがいやならこのように修正するのもよいでしょう。
上の関数はこのように呼び出すことができます。
関数をりタンする関数
上の例ではイメージをリターンするが、今回は関数をリターンしてみよう。
関数から値として返された関数を見たことがない方は息が詰まるかもしれないが、とりあえずゆっくりみてみよう。
下線を引いた部分はリターンされる関数です。
関数をリターンするために fという関数を作りました。
f
は im
でリターンされているイメージだけを持ってますし、それをリターンします。
上の関数をよりSwift化した形です。関数名`f`も必要ないです。
リターンされる関数前の`return`も省略可能です。
キャプチャされた変数を設定(set)します。
簡単な例です。
キャプチャした環境を保存するクロージャ
ある関数は直接呼び出されるのではなく後で実行するため、その関数が保存される(その環境をとらえ、時間の経過とともに保存する)クロージャをescaping closure
と言います。(上のように@escaping
をつきます。)
次のようなcountedGreet()
を呼びだすとカウントされた値が出力されます。
一体どこで変数をカウントするでしょうか。
変数count
はローカル関数(匿名関数)で宣言されてないですが、それを利用して0に初期化され、後にカウントしています。
もし、count
が匿名関数内で宣言された場合、countedGreet()
が呼び出されるたびに ct
を0に設定します。
それは、countedGreet()
が呼び出されるたびにインクリメントするように、ある親密的な環境にcountedGreet()
が保持されるからです。
参考
iOS13 Programming Fundamentals with Swift, Matt Neuburg(2019) p50 - 58