完了ハンドラーがある次の関数がありますが、このエラーが発生します。
Closure use of non-escaping parameter may allow it to escape
これが私のコードです:
func makeRequestcompletion(completion:(_ response:Data, _ error:NSError)->Void) {
let urlString = URL(string: "http://someUrl.com")
if let url = urlString {
let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, urlRequestResponse, error) in
completion(data, error) // <-- here is I'm getting the error
})
task.resume()
}
}
あなたの助けに本当に感謝します
クロージャがエスケープできることを明示的に定義する必要があるようです。
クロージャーは、クロージャーが引数として関数に渡されたときに関数をエスケープすると言われていますが、関数が戻った後に呼び出されます。クロージャをパラメータの1つとして受け取る関数を宣言する場合、パラメータのタイプの前に@escapingを記述して、クロージャがエスケープを許可されていることを示すことができます。
TLDR; @escaping
補完変数の後のキーワード:
func makeRequestcompletion(completion: @escaping (_ response:Data, _ error:NSError)->Void) {
let urlString = URL(string: "http://someUrl.com")
if let url = urlString {
let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, urlRequestResponse, error) in
completion(data, error) // <-- here is I'm getting the error
})
task.resume()
}
}
「エスケープ」クロージャーは、それが作成されたスコープを存続させることができるクロージャーです。エスケープクロージャーは、参照カウントとメモリー管理に関して特別な注意を必要とし、最適化が難しくなる可能性があります。
Swift 3以前は、クロージャーのデフォルトはエスケープしていると想定していました。これは、開発者が既知のクロージャーを具体的に特定する必要があることを意味しましたnotエスケープして許可する最適化を行うコンパイラー。コミュニティーは、実際には、クロージャーがエスケープするかどうかをコンパイラー自体が簡単に検出できることを発見し、エスケープへの積極的なアプローチがより高速なコードにつながる可能性があることを決定しました。エスケープしないと見なされ、@escaping
属性でエスケープしているクロージャーにフラグを立てる必要があります。
あなたの場合、URLSession.shared.dataTask
が受け入れるクロージャ自体がエスケープクロージャであるため、その内部でクロージャを使用する場合は、@escaping
もマークする必要があります。
@escaping
はすべての呼び出しメソッドに対して感染性があり、コンパイラーは、いつmustを含める必要があるかを決定します。
次の例(コンパイル)を考えてみます。
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: ()->()) {
dispatchNow(block)
}
func dispatchNow(_ block: ()->()) {
block()
}
ただし、この変更例では、タイプnon-escaping parameter may allow it to escape
の-twoエラーが生成されます。
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: ()->()) {
dispatchLater(block)
}
func dispatchLater(_ block: ()->()) {
DispatchQueue.main.async(execute: block)
}
MainでのディスパッチはdispatchLater
メソッドが@escaping
を必要とすることを意味し、それを追加したらdispatchSometime
メソッドalsoは@escaping
を必要としますサンプルをコンパイルします。
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: @escaping ()->()) {
dispatchLater(block)
}
func dispatchLater(_ block: @escaping ()->()) {
DispatchQueue.main.async(execute: block)
}
ただし、要点は次のとおりです。
@escaping
を呼び出しチェーンに追加し続けます。weak
を使用するように注意してください」という警告です。意味
これが本当に楽しいのは、いくつかのメソッドを調整して@escaping
キーワードを含める必要がある場合です。これにより、コンパイラーは文句を言わなくなります。ただし、これらのメソッドが実際にプロトコルに準拠している場合、そのプロトコルのメソッドはalso@escaping
キーワードを取得する必要があり、これは他のすべてのプロトコル準拠にも感染します。楽しい!