gpt4 book ai didi

swift - 为什么 Swift 3 需要 @escaping 注解?

转载 作者:搜寻专家 更新时间:2023-10-31 22:12:10 24 4
gpt4 key购买 nike

我读了这个question and answersCocoacasts blog post并且我完全理解什么是 @escaping 注释。

但老实说,我根本不明白为什么我们需要它。

上面的 Cocoacasts 博客文章指出:

There are several benefits to make closures non-escaping by default. The most obvious benefits are performance and the ability for the compiler to optimize your code. If the compiler knows that a closure is non-escaping, it can take care of a many of the nitty-gritty details of memory management.

但 Swift 编译器可以确定是否缺少 @escaping 并在这种情况下显示错误,因此如果我们从 Swift 语言中删除 @escaping 注释,编译器仍然可以看到当闭包没有逃脱时,我们可以让他在这种情况下应用优化。

This also means that you can use the self keyword without issues in non-escaping closures because the closure is invoked before the function returns. There is no need to use a weak reference to self in the closure. This is a nice benefit you get for free.

但是如果闭包参数被标记为 @escaping 我仍然可以传递使用对 self 的强引用的闭包并且编译器不会显示任何警告。实际上,如果在 @escaping 闭包中捕获的所有引用在默认情况下都是 weak 并且应用特殊关键字使它们变强,这会更有用。

我还认为可能是 @escaping 注释是通过显式声明此闭包参数不会转义函数体来使代码 self 记录的方式,但调用的目的是什么边?它不限制闭包的定义方式,也不阻止调用方使用强引用。所以我只剩下希望调用方仔细查看函数签名并采取适当的措施(例如使用弱引用)。

所以问题是为什么我们真的需要 Swift 3 中的 @escaping 闭包,在哪些情况下我们不能没有它?

更新:

我知道不转义闭包不能传递给闭包参数标记为@escaping的函数:

func testNoEscape(f: () -> ()) {
f()
}

var storeF: (() -> ())?

func testEscaping(f: @escaping () -> ()) {
storeF = f
}

func tryPassNoEscapeToEscaping(f: () -> ()) {
testEscaping(f: f)
}

导致编译错误:

passing non-escaping parameter 'f' to function expecting an @escaping closure

但这是 @escaping 闭包带来的唯一真正限制,它看起来像是围绕自身构建的,并没有提供任何其他好处。

更新 2

虽然我在上面正确地阐述了我的想法,但我最后的问题是不准确的。

真正的问题是,如果编译器可以自行检测转义闭包并且 @escaping 注释不对参数值施加任何限制,为什么我们需要 @escaping 注释?

在我看来,如果编译器不允许我们在转义闭包时做一些坏事,比如使用 self 和其他强引用,那么它会更有用。或者,如果转义闭包是某种特殊类型,我们必须在使用转义闭包参数调用函数时提及:

func f(c: () -> ()) { // c is escaping from f somehow
// ...
}

f escaping { // have to use `escaping` keyword
// ...
}

所以调用方不必查看f 签名就知道c 正在转义,因为如果它试图通过非转义闭包,它会得到编译错误作为转义闭包参数值。

在当前的实现中,想要在代码中使用 f 的开发人员必须查看 f 签名以了解 c 将转义,这是不安全,因为这要求最初编写此代码并在以后修改它的任何人都必须详细了解 f 签名,这是不可靠的,并且此类代码不是 self 记录的。

我明白,也许我的问题不适合SO。对此感到抱歉。

如果是这样,如果我无法从使用 Swift 语言和编译器实现转义逻辑的人那里得到答案,我将稍后关闭它。

最佳答案

非转义闭包可以做转义闭包做不到的事情。它们是完全不同的动物。

例如,非转义闭包可以引用 self 的属性,而无需明确说明 self。这是因为,由于是非转义的(即它在收到后立即执行),因此没有以某种棘手的方式捕获 self 并导致保留周期的危险。

并且,非转义闭包可以关闭 inout 参数。但这对于转义闭包毫无意义,因此是不允许的。

如果闭包看起来有时需要self有时不需要self,那将是非常神秘的,有时允许关闭 inout有时则不允许。 @escaping 注释使此类规则区分清晰且一致。

关于swift - 为什么 Swift 3 需要 @escaping 注解?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42531063/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com