如何在函数中存储非转义闭包?

how to store non escaping closure inside a function?

提问人:Dev karan 提问时间:5/18/2023 最后编辑:Dev karan 更新时间:5/18/2023 访问量:58

问:

我们试图在函数中存储非转义闭包,它给了我们下面提到的错误。

error: Converting non-escaping parameter 'completionHandler' to generic parameter 'Element' may allow it to escape

根据定义:“一旦函数体被执行,一个不可转义的闭包就会超出范围并停止存在于内存中。

func someFunctionWithNonEscapingClosure(completionHandler: () -> Void) { 
   var completionHandlers: [() -> Void] = []
   completionHandlers.append(completionHandler)
 }

谁能解释这种行为?

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures

iOS Swift 关闭

评论

0赞 Geoff Hackworth 5/18/2023
可能相关:forums.swift.org/t/...
0赞 Geoff Hackworth 5/18/2023
您的函数似乎名称令人困惑,因为它需要一个转义闭包,而您的问题似乎是关于将该闭包暂时存储在不会超过函数调用的局部变量中。someFunctionWithEscapingClosure

答:

2赞 Paulw11 5/18/2023 #1

您正在将对闭包的引用存储在数组中。数组的泛型类型现在是 - 您的闭包类型。但是,Swift 编译器对这个数组的处理方式与另一个数组没有任何区别。它“不知道”数组包含闭包的方式,可以让它检查闭包是否转义。Element() -> Void

想象一下,如果你的代码看起来像这样:

var myCompletionHander: (()->Void)?

func someFunctionWithNonEscapingClosure(completionHandler: () -> Void) { 
   self.myCompletionHandler = completionHandlers
 }

编译器可以看到闭包已转义并给出错误。

现在,想象一下这是你的代码:

var myCompletionHanders = [()->Void]()

func someFunctionWithNonEscapingClosure(completionHandler: () -> Void) { 
   var completionHandlers: [() -> Void] = []
   completionHandlers.append(completionHandler)
   self.myCompletionHandlers = completionHandlers
 }

同样,闭包已转义,但编译器无法就此发出警告,因为转义是数组赋值的副作用。数组赋值仅检查数组类型是否兼容,而不检查类型是否为非转义闭包。ElementElement

一些背景来自 Geoff 在评论中链接的 Swift.org 论坛帖子:

但是,编译器仅对函数类型执行此分析。这意味着假定其他类型始终处于转义状态 - 您可以自由地存储类引用,复制值类型等。的签名如下所示:withUnsafePointer(to:_:)

func withUnsafePointer<T, Result>(to value: T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result

由于 value 参数的类型为 T,而不是函数类型,因此编译器必须假定在 withUnsafePointer 的主体中,value 参数可能会转义。这意味着将转义闭包作为 value 参数的参数传递是无效的。

您在这里有一个类似的问题 - 数组的泛型参数是类型,而不是函数类型 - 因此假定它是转义的。Element