Swift 3 :Closure use of non-escaping parameter may allow it to escape

扶醉桌前 提交于 2019-11-30 07:11:03

问题


I have the following function where I have completion handler but I'm getting this error:

Closure use of non-escaping parameter may allow it to escape

Here is my code:

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()
    }
}

Any of you knows why I'm getting this error?

I'll really appreciate you help


回答1:


Looks like you need to explicitly define that the closure is allowed to escape.

From the Apple Developer docs,

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.

TLDR; Add the @escaping keyword after the completion variable:

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()
    }
}



回答2:


An "escaping" closure is a closure that can outlive the scope that it was created in. Escaping closures require special care around reference counting and memory management and can be harder to optimize.

Prior to Swift 3, the default for closures was to assume that they were escaping. This meant that developers had to specifically identify closures that are known not to escape to allow the compiler to make optimizations. The community found that in fact, the compiler could easily find out by itself if a closure is escaping or not, and decided that an aggressive approach to escaping could result in faster code. The result is that closures are now assumed to be non-escaping, and you need to flag closures that are escaping with the @escaping attribute.

In your case, the closure that URLSession.shared.dataTask accepts is itself an escaping closure, so if you use a closure inside of it, it also needs to be marked @escaping.




回答3:


@escaping is infectious to all calling methods, and the compiler determines when you must include it.

Consider this example (which compiles):

dispatchSometime( { print("Oh yeah") })

func dispatchSometime(_ block: ()->()) {
    dispatchNow(block)
}

func dispatchNow(_ block: ()->()) {
    block()
}

This modified example, however, produces two errors of type non-escaping parameter may allow it to escape:

dispatchSometime( { print("Oh yeah") })

func dispatchSometime(_ block: ()->()) {
    dispatchLater(block)
}

func dispatchLater(_ block: ()->()) {
    DispatchQueue.main.async(execute: block)
}

The dispatch on main means the dispatchLater method needs @escaping, and once you've added that, the dispatchSometime method also requires @escaping for the example to compile.

dispatchSometime( { print("Oh yeah") })

func dispatchSometime(_ block: @escaping ()->()) {
    dispatchLater(block)
}

func dispatchLater(_ block: @escaping ()->()) {
    DispatchQueue.main.async(execute: block)
}

However, the take away is just:

  • Keep adding @escaping up the call chain until the compiler stops complaining.
  • The keyword doesn't change anything: it's a warning which says, essentially, "be careful to use weak with captured variables as they may be retained along with the block itself."

Implications

The really fun case with this is where you have to adjust several methods to include the @escaping keyword, which gets the compiler to stop complaining. However, if those methods are actually conforming to a protocol, that protocol's methods must also get the @escaping keyword, which also infects all other protocol conformants. Fun!



来源:https://stackoverflow.com/questions/42214840/swift-3-closure-use-of-non-escaping-parameter-may-allow-it-to-escape

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!