🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

1回答

1668閲覧

swiftのクロージャーのescaping属性について

oeiqgfodgfhps

総合スコア35

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

2グッド

1クリップ

投稿2020/12/29 16:47

swiftのクロージャーの@escapingについていろいろ調べていたら、少しわからないことがあったので質問させてください。
@escapingに関して、自分はクロージャーを関数のスコープ外の変数などに保存しておく時に必要なものというふうに認識をしていました。

しかしこの記事をみたところ、非同期処理にも@escapingが必要と記述してあり少し混乱しています。

結局のところ@escapingはクロージャーを関数のスコープ外の変数に保存し、かつ非同期処理を行う時に必要な属性ということなのでしょうか?それともクロージャーを関数のスコープ外の変数に保存する、または非同期処理を行うときに必要な属性という解釈をすればいいのでしょうか??

miyabi_pudding, YutaMatsuura715👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyabi_takatsuk

2020/12/29 17:20

その記事と、解釈では、混乱するのも無理ないかと。 https://qiita.com/mishimay/items/1232dbfe8208e77ed10e この記事の方がより、仕様に則った説明がされています。 保存しておく、ではなく、あくまで参照の理解が必要な気がします。 (かと言って、ぶっちゃけ自信ないので、回答ではなくこちらで)
guest

回答1

0

非同期処理も「スコープ外の変数に保存する」のと同じであることを理解するのが良さそうな気がします。

@escaping が必要になるのは、クロージャーが内側にキャプチャー(クロージングオーバー)する変数が、通常のスコープを超えて存在する可能性がある場合に必要になります。

非同期処理を行うメソッドにクロージャーを渡す場合、別のスレッドにクロージャーを渡した後に、それが実行されるのを待たずに現在のスコープが終了します。このとき渡したクロージャーは、別のスレッドで処理を実行するために、渡された側が「元のスコープ外の変数に保存しておく」ことになります。そうしないと、別スレッドでそのクロージャーを実行する前に、元のスコープが終わって破棄されてしまう可能性が出てきてしまうため、実行先のスレッドで、そのクロージャーを使い終わるまでの間は保存しておく必要があります。

Swift の非同期処理ライブラリー Dispatchsync メソッドと async メソッドの定義の違いももしかすると何かの参考になるかもしれないので、説明用に要所だけ切り抜いた形で挙げておきます。

swift

1class DispatchQueue { 2 /* 3 非同期処理は @escaping として 4 クロージャーを受け取る設計になっています。 5 非同期処理は、このスコープが終わった後に実行タイミングがくる 6 可能性があるため、渡したクロージャーがこのスコープを抜けても 7 生存しているように、外部に保存しておく必要があるためです。 8 */ 9 public func async(execute work: @escaping @convention(block) () -> Void) 10 11 /* 12 同期処理は @escaping なしで 13 クロージャーを受け取る設計になっています。 14 非同期処理なら、その処理が終わるまでこのスコープを 15 抜けることがないため、外部に保存しておく必要がありません。 16 */ 17 public func sync<T>(execute work: () throws -> T) rethrows -> T 18}

swift

1func postMessage() { 2 3 // このクロージャーのスコープは `postMessage` 関数内のブロックです。 4 let message: () -> Void = { 5 } 6 7 /* 8 非同期的な実行により `message` がこのスコープを 9 抜けた後に実行される可能性が「ある」ため `@escaping` として渡されます。 10 */ 11 messageQueue.async(execute: message) 12 13 /* 14 同期的な実行により `message` がこのスコープを 15 抜けた後に実行される可能性が「ない」ため `@noescape` として渡されます。 16 */ 17 messageQueue.sync(execute: message) 18}

投稿2020/12/29 17:23

TomohiroKumagai

総合スコア441

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問