Compiler error Closure use of non-escaping parameter 'completion' may allow it to escape
, Which make sense because it will be called after the function return.
func sync(completion:(()->())) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion()
}
}
But if I make closure optional then no compiler error, Why is that? closure can still be called after the function returns.
func sync(completion:(()->())?) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion?()
}
}
Wrapping a closure in an Optional automatically marks it escaping. It's technically already "escaped" by being embedded into an enum (the Optional).
For understanding the case, implementing the following code would be useful:
typealias completion = () -> ()
enum CompletionHandler {
case success
case failure
static var handler: completion {
get { return { } }
set { }
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler.handler = handlerParameter
}
At the first look, this code seems to be legal, but it's not! you would get compile-time error complaining:
error : assigning non-escaping parameter 'handlerParameter' to an @escaping closure
let chObject = CompletionHandler.handler = handlerParameter
with a note that:
note : parameter 'handlerParameter' is implicitly non-escaping func doSomething(handlerParameter: completion) {
Why is that? the assumption is that the code snippet has nothing to do with the @escaping
...
Actually, since Swift 3 has been released, the closure will be "escaped" if it's declared in enum , struct or class by default.
As a reference, there are bugs reported related to this issue:
Although they might not 100% related to this case, the assignee comments are clearly describe the case:
The actual issue here is that optional closures are implicitly @escaping right now.
That is unfortunately the case for Swift 3. Here are the semantics for escaping in Swift 3:
1) Closures in function parameter position are non-escaping by default
2) All other closures are escaping
Thus, all generic type argument closures, such as Array and Optional , are escaping.
Obviously, Optional
is enum.
Also -as mentioned above-, the same behavior would be applicable for the classes and structs:
Class Case:
typealias completion = () -> ()
class CompletionHandler {
var handler: () -> ()
init(handler: () -> ()) {
self.handler = handler
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
Struct Case:
typealias completion = () -> ()
struct CompletionHandler {
var handler: completion
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
The two above code snippets would leads to the same output (compile-time error).
For fixing the case, you would need to let the function signature to be :
func doSomething( handlerParameter: @escaping completion)
Since you are expecting that you have to let the completion:(()->())?
to be escaped, that would automatically done -as described above-.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.