@エスケープ、@非エスケープ、@autoclosure、およびカレー関数を分かりやすく説明します
クロージャは、コード内で渡されて使用できる自己完結型の機能ブロックです。
-Apple
クロージャは、定義されているコンテキストから任意の定数や変数への参照をキャプチャして格納することができます。 クロージャは、独自の名前を持たず、その環境から値をキャプチャする関数であると考えることができます。 それらを格納し、関数に引数として渡し、他の値やオブジェクトと同じように扱うことができます。 完了ハンドラとしてクロージャを渡すことは、多くのApiで一般的なパターンです。 標準のSwiftライブラリは、主にイベント処理とコールバックのためにクロージャを使用します。
関数は、特定のタスクを実行する自己完結型のコードのチャンクです。 この名前は、必要に応じてそのタスクを実行するために関数を「呼び出す」ために使用されます。 関数を定義するには、func
キーワードを使用します。 関数は、多くのパラメータ、可変長パラメータにnoneを取り、noneまたは複数のパラメータを返すことができます。
関数型
関数型は、パラメータ型と関数の戻り値の型で構成されています。 上記の例では、関数の型は次のようになります:(Int, Int) -> Int
これは次のように読むことができます:”タイプInt
の両方の2つのパラメータを持ち、タイプInt
の値を返す関数。”関数型は、関数のパラメータまたは戻り値の型として設定することができます。
関数型は、次のように任意の変数に割り当てることができます:
var mathFunction: (Int, Int) -> Int = add
関数はクロージャの特殊なケースです。 クロージャは次の三つの形式のいずれかを取ります:
- グローバル関数:名前があり、値をキャプチャできません。
- ネストされた関数:名前を持ち、それを囲む関数から値を取得できます。
- クロージャ式:名前がなく、周囲のコンテキストから値をキャプチャできます。
クロージャ式:
Closureは、中括弧の中に関数型を入れ、戻り値の型の後にin
キーワードを入れることで作成できます。
省略形引数名
クロージャ引数は、位置を参照することができます。 ,
,
,
というように。
でクロージャからの暗黙的な戻り値:
単一式クロージャは、宣言からreturn
キーワードを省略することにより、単一式の結果を暗黙的に返すことができます。
複数行式クロージャの場合、return
キーワードは省略できません。
:
関数の最後の引数としてクロージャ式を関数に渡す必要があり、クロージャ式が長すぎる場合は、末尾のクロージャとして書くことができます。 末尾のクロージャは、関数の引数であっても、関数呼び出しのかっこ()の後に書き込まれます。 末尾のクロージャ構文を使用する場合は、関数呼び出しの一部としてクロージャの引数ラベルを記述しません。
closureがメソッドの最後のパラメータである場合、swiftは次のように書くことができます🖕
末尾のクロージャ構文を使用すると、クロージャ全体をreduce(_:)
メソッドの外側の括弧内にラップする必要なく、クロージャがサポートする関数の直後にクロージャの機能をきれいにカプセル化します。
値のキャプチャ:
クロージャは、定義されている周囲のコンテキストから定数と変数をキャプチャできます。 その後、定数と変数を定義した元のスコープが存在しなくなった場合でも、クロージャはそれらの定数と変数の値を本体内から参照して変更できます。
Swiftでは、値をキャプチャできるクロージャの最も単純な形式は、別の関数の本体内に記述されたネストされた関数です。 ネストされた関数は、外部関数の引数のいずれかをキャプチャすることができ、外部関数内で定義された定数と変数をキャプチャすることもで
このmakeIncrementer
関数は、1つの引数、つまりIntを入力として受け入れ、関数型、つまり() -> Int
を返します。 これは、単純な値ではなく関数を返すことを意味します。 返される関数にはパラメータがなく、呼び出されるたびにInt
値を返します。
ここでamount
は引数であり、runningTotal
は変数として宣言され、0で初期化されます。 ネストされた関数incrementer
は、周囲のコンテキストからamount
とrunningTotal
をキャプチャします。
makeIncrementer
を実際に見てみましょう:
メモ: 最適化として、Swiftは代わりに、その値がクロージャによって変更されていない場合、およびクロージャが作成された後に値が変更されていない場合、値のコ
Swiftは、変数が不要になったときに変数を破棄することに関連するすべてのメモリ管理も処理します。
関数の引数で長いクロージャ式を取り除くには、typealiasを使用できます。
非エスケープクロージャ:
クロージャパラメータは、Swift3より前にデフォルトでエスケープされていました。 Swift3では、クロージャパラメータが非エスケープ
としてマークされている場合、クロージャは関数本体をエスケープしません。 関数の引数としてクロージャを渡すと、クロージャは関数の本体で実行され、コンパイラが返されます。 実行が終了すると、渡されたクロージャはスコープ外になり、メモリ内にはもう存在しません。
少なくとも知っておく必要があります
クロージャの実行をエスケープしたい場合は、クロージャのパラメータで@escapingを使用する必要があります。
非エスケープクロージャのライフサイクル:
1。 関数呼び出し中に、関数の引数としてクロージャを渡します。
2. 関数内でいくつかの作業を行い、クロージャを実行します。
3. 関数が返されます。
より良いメモリ管理と最適化のために、Swiftはすべてのクロージャをデフォルトでエスケープしないように変更しました。 CaptureList.swift
はエスケープしないクロージャの例です。
注:@非エスケープ注釈は、関数型
エスケープするクロージャにのみ適用されます:
クロージャは、クロージャが関数に引数として渡されたときに関数をエスケープすると言われますが、関数が戻った後に呼び出されます。 クロージャを@escaping
でマークすると、クロージャ内でself
を明示的に参照する必要があります。
1. 関数呼び出し中に、関数の引数としてクロージャを渡します。
2. 関数内でいくつかの追加作業を行います。
3. 関数クロージャを非同期的に実行するか、または格納します。
4. 関数が返されます。
クロージャがデフォルトでエスケープされている場所を見てみましょう:
- 関数型の変数は暗黙的なエスケープです
- 型エイリアスは暗黙的なエスケープです
- オプションのクロージャは暗黙的なエスケープです
一般的なエラー:
非エスケープクロージャをエスケープクロージャに割り当てます。 これを修正するには2つの方法があります:
- クロージャをエスケープ
- としてマークするか、クロージャをオプション
Autoclosures:
Swiftの@autoclosure
属性を使用すると、自動的にクロージャにラップされる引数を定義できます。 引数を取らず、呼び出されると、その中にラップされている式の値を返します。 この構文上の利便性により、明示的なクロージャの代わりに通常の式を記述することにより、関数のパラメータの周りに中括弧を省略できます。
たとえば、assert(condition:message:file:line:)
関数はcondition
パラメーターとmessage
パラメーターのオートクローズを受け取ります。condition
パラメーターはデバッグビルドでのみ評価され、message
パラメーターはcondition
がfalse
の場合にのみ評価されます。
func assert(_ expression: @autoclosure () -> Bool,
_ message: @autoclosure () -> String) {}
@autoclosure
を@escaping
属性構文で使用するには、次のようにします:
@autoclosure @escaping () -> Bool
クロージャ対ブロック:
“SwiftクロージャとObjective-Cブロックは互換性があるため、ブロックを期待するObjective-CメソッドにSwiftクロージャを渡すことができます。 Swiftのクロージャと関数は同じ型を持っているので、Swift関数の名前を渡すことさえできます。 クロージャはブロックと同様のキャプチャセマンティクスを持っていますが、一つの重要な方法が異なります。 言い換えれば、Objective-Cの__blockの動作は、Swiftの変数のデフォルトの動作です。”
クロージャ対デリゲート:
解決策は問題に依存します。 また、Appleはコールバックパターンに焦点をシフトしています。 UIAlertAction
はその一例です。
https://medium.com/@abhimuralidharan/functional-swift-all-about-closures-310bc8af31dd
https://medium.com/@kumarpramod017/what-do-mean-escaping-and-nonescaping-closures-in-swift-d404d721f39d
https://oleb.net/blog/2016/10/optional-non-escaping-closures/
https://swiftunboxed.com/lang/closures-escaping-noescape-swift3/
https://medium.com/@johnsundell/using-autoclosure-when-designing-swift-apis-67fe20a8b2e