Escapingクロージャとは、呼び出し元の関数のスコープを"離れる"クロージャ(例えば、非同期実行のために保存されるもの)です。
Swiftでは、デフォルトで関数はnon-escapingクロージャを受け取ります:クロージャは関数の呼び出し内で実行されます。
escapingを明示的に指定するには、@escapingキーワードを使用します:
func asyncTask(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }
主な違い:
[weak self]または[unowned self]を指定する必要があります。DispatchQueue.asyncを呼び出す関数のパラメータとして渡されるクロージャには、常に@escapingを書く必要がありますか?
— はい。DispatchQueue.asyncはクロージャを実行時まで保存するため、クロージャはescapingになります。
例:
func foo(action: () -> Void) { DispatchQueue.main.async { action() // コンパイルされません:クロージャはescapingである必要があります。 } } // 必要なのは: func bar(action: @escaping () -> Void) { ... }
事例
コントローラがescapingクロージャ内でselfへの強い参照を作成した(例えば、ネットワークリクエスト)。コントローラは画面から離れても解放されなかった — 強いretain cycle。解決策:[weak self]または[unowned self]を使用する。
事例
関数がDispatchQueue.asyncにクロージャを渡したが、それをescapingとしてマークしなかった。プロジェクトはコンパイルされず、エラーは関数の入れ子構造のために見つけにくかった。
事例
クロージャ内で、クロージャが呼び出される時点で既にデイニシャライズされたオブジェクトにアクセスした([unowned self]を使用)。結果 — ランタイムクラッシュ。解決策:[weak self]を使用し、nilチェックを行う。