Swift 3:关闭使用非转义参数可能允许它逃脱

时间:2017-02-13 22:38:21

标签: ios swift xcode8 completionhandler

我有以下功能,我有完成处理程序,但我收到此错误:

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

enter image description here 你们中的任何人都知道我为什么会收到这个错误?

我真的很感谢你的帮助

3 个答案:

答案 0 :(得分:8)

看起来你需要明确定义允许关闭转义。

来自Apple Developer docs

  

当闭包作为参数传递给函数时,闭包被称为转义函数,但在函数返回后调用。当声明一个以闭包作为其参数之一的函数时,可以在参数的类型之前编写@escaping,以指示允许闭包转义。

TLDR;在完成变量之后添加class common { friend class mode1; friend class mode2; protected: volatile uint8_t& reg1; volatile uint8_t& reg2; uint8_t data; public: virtual void operation2() final { // do something }; }; class mode1 : public virtual common { public: virtual void operation1() final { // do something }; virtual void operation3() final { // do something } }; }; class mode2 : public virtual common { public: virtual void operation4() final { // do something } virtual void operation5() final { // do something } }; class mode1and2 : public mode1, public mode2 { public: void operation6() { // do something } }; void operation7() { // do something } }; }; 关键字:

@escaping

答案 1 :(得分:3)

&#34;逃避&#34;闭包是一个闭包,它可以比它创建的范围更长。转出闭包需要特别注意引用计数和内存管理,并且可能更难以优化。

在Swift 3之前,闭包的默认设置是假设它们正在转义。这意味着开发人员必须专门识别已知 not 的闭包以允许编译器进行优化。社区发现事实上,编译器可以很容易地找出闭包是否转出,并决定一种积极的转义方法可以导致更快的代码。结果是现在假定闭包是非转义的,并且您需要标记使用@escaping属性转义的闭包。

在你的情况下,URLSession.shared.dataTask接受的闭包本身就是一个转义闭包,所以如果在其中使用闭包,它也需要标记为@escaping

答案 2 :(得分:1)

@escaping对所有调用方法都有感染力,编译器会确定必须包含它的时间。

考虑这个例子(编译):

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

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

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

但是,此修改示例会产生类型为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)
}

在main上发送意味着dispatchLater方法需要@escaping,一旦您添加了该方法,dispatchSometime方法需要{{ 1}}用于编译的示例。

@escaping

然而,带走只是:

  • 继续在调用链上添加dispatchSometime( { print("Oh yeah") }) func dispatchSometime(_ block: @escaping ()->()) { dispatchLater(block) } func dispatchLater(_ block: @escaping ()->()) { DispatchQueue.main.async(execute: block) } ,直到编译器停止抱怨。
  • 该关键字不会改变任何内容:它是一个警告,它基本上表示&#34;小心使用@escaping捕获的变量,因为它们可能与块本身一起保留&#34;

<强>启示

真正有趣的情况是你需要调整几个方法来包含weak关键字,这会让编译器停止抱怨。但是,如果这些方法实际上符合协议,那么该协议的方法必须获取@escaping关键字,这也会感染所有其他协议符合性。有趣!