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

uoifb46i  于 2023-05-19  发布在  iOS
关注(0)|答案(1)|浏览(93)

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

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

mnemlml8

mnemlml81#

您正在将对闭包的引用存储在数组中。数组Element的泛型类型现在是() -> Void- Your closure type。但是,Swift编译器并没有将这个数组与另一个数组区别对待。它并不“知道”数组中包含闭包,因此无法检查闭包是否转义。
想象一下,如果你的代码看起来像这样:

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
 }

同样,闭包已经转义,但编译器不能警告您,因为转义是作为数组赋值的副作用发生的。数组赋值只检查数组Element类型是否兼容,而不检查Element类型是否是非转义闭包。
一些背景来自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类型,而不是函数类型--所以假设它是转义的。

相关问题