web-dev-qa-db-ja.com

クロージャーをSwift 3に更新する-@escaping

コードをXcode 8.0 beta 6に更新しましたが、新しい非エスケープクロージャーのデフォルトに関するものに固執しました。次のコードでは、Xcodeは、以下のコードの最初の行の@escapingの前にcompletion:を追加することを提案していますが、それでもコンパイルされず、円になります。 *

EDIT:実際には、Xcodeが示唆するように、aftercompletion:に@escapingを追加する必要があります。アラートは表示されますが、クリーニングとコンパイルにより削除されます。)*更新されたSwift 3で動作するように、このコードをどのように再作成/修正する必要がありますか?新しいマニュアルを確認しましたが、適切なコードサンプルが見つかりませんでした。

func doSomething(withParameter parameter: Int, completion: () -> ()) {
    // Does something

    callSomeOtherFunc(withCompletion: completion)
  }

// Calling the method and execute closure 
doSomething(withParameter: 2) {
  // do things in closure
}

助けていただければ幸いです!

75
nontomatic

Swift 3:クロージャーパラメーターの属性は、パラメーターtypeに適用され、パラメーター自体には適用されません

Swift 3より前は、クロージャー属性@autoclosureおよび@noescapeはクロージャーparameterの属性でしたが、現在はパラメーターtype;次の承認済みSwift進化の提案を参照してください。

特定の質問は、パラメータタイプ属性@escaping(同じ新しいルールが適用されます)に関係します。これは、受け入れられたSwift進化の提案で説明されているように、デフォルトでクロージャパラメータをエスケープしないようにします。

これらの提案は現在、Xcode 8のベータ段階で実装されています( Xcode 8ベータ6のリリースノート ;アクセスには開発者アカウントログインが必要です)

Xcode 8ベータ6の新機能-Swiftコンパイラ:Swift言語

閉鎖パラメーターは、@noescapeで明示的に注釈が付けられるのではなく、デフォルトでは非エスケープです。 @escapingを使用して、クロージャーパラメーターがエスケープされる可能性があることを示します。 @autoclosure(escaping)は、@autoclosure @escapingとして記述されています。注釈@noescapeおよび@autoclosure(escaping)は非推奨です。 (SE-0103)

...

Xcode 8ベータ版の新機能– SwiftおよびApple LLVMコンパイラ:Swift言語

@noescapeおよび@autoclosure属性は、パラメーター名の前ではなく、パラメータータイプの前に記述する必要があります。 [SE-0049]

したがって、次のようにデフォルト以外の@escaping属性を使用します。パラメーター自体ではなく、クロージャーパラメーターのtypeに適用されます

func doSomething(withParameter parameter: Int, completion: @escaping () -> ()) {
    // ...
}

(コメントはSOに関する永続的なデータではないため、以下の投票されたコメントの質問に対する私の答えを含む)

@Cristi Băluță: "エスケープは何をしますか?Swift3自動変換の前にこのキーワードを見たことはありません..."

例参照 上記のSE-0103進化の提案 へのリンク(およびベータ6リリースノートの引用テキスト):以前は、クロージャーパラメーターはデフォルトでエスケープされていました(したがって、明示的に存在する必要はありません)エスケープ用のアノテーション)が、デフォルトでは代わりに非エスケープになりました。したがって、@escapingを追加して、クロージャーパラメーターがエスケープする可能性があることを明示的に注釈します(既定の動作とは逆)。これはまた、@noescapeが非推奨になった理由を説明します(デフォルトの動作に注釈を付ける必要はありません)。

クロージャーパラメーターがエスケープしていることの意味を説明するために、 言語リファレンス-属性 を引用しています。

「メソッドまたは関数宣言のパラメーターの型にこの属性を適用して、後で実行するためにパラメーターの値を保存できることを示します。つまり、この値は呼び出しの存続期間を超えます。」

58
dfri

@noescape

Xcode 8ベータ6以降@noescapeがデフォルトです。それ以前は、@escapingがデフォルトでした。以前のバージョンからSwift 3.0に更新する人は誰でもこのエラーに直面する可能性があります。

@noescapeクロージャーを変数内に保存することはできません。なぜなら、変数内にクロージャーを格納できるなら、コードのどこからでもクロージャーを実行できるからです。ただし、@noescapeは、クロージャーパラメーターが関数の本体をエスケープできないことを示しています。

これにより、Xcode 8でコンパイラエラーが発生します。

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: () -> ()) {
        myClosure = finishBlock    // ‼️ Error: Assigning non-escaping parameter 'finishBlock' to an @escaping closure
    }
}

これでコンパイルできます(明示的に@escapingと記述します)

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: @escaping () -> ()) {
        myClosure = finishBlock
    }
}

@noescapeの利点:

  • コンパイラはパフォーマンスを向上させるためにコードを最適化できます
  • コンパイラーがメモリー管理を処理できます
  • クロージャーで自己への弱い参照を使用する必要はありません


詳細については、以下を参照してください。 非エスケープクロージャをデフォルトにする

22