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

问题描述 投票:0回答:1

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

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

根据定义:“一旦函数体被执行,非转义闭包就会超出范围并停止存在于内存中。”但我们在函数中使用它

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

谁能解释这种行为?

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

ios swift closures
1个回答
1
投票

您正在将对闭包的引用存储在数组中。你的数组

Element
的通用类型现在是
() -> Void
- 你的闭包类型。但是,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

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

你在这里有一个类似的问题——数组的泛型参数是

Element
类型,而不是函数类型——所以它被认为是转义的。

© www.soinside.com 2019 - 2024. All rights reserved.