Swift @escaping 仅适用于非空函数参数?

dan*_*ing 6 ios swift

我从来没有真正理解何时使用@escaping。我理解它的作用(即转义闭包和非转义闭包之间的区别),但tbf我一直依赖Xcode来告诉我何时将修饰符添加到我的参数中。

我的问题是,为什么这种情况@escaping只适用于非零闭包?这就是我的意思:

func someFunc(someArg: Int, callback: @escaping (Error?) -> Void) {
    DispatchQueue.global(qos: .background).async {
    ...
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面,如果我不添加@escapingXcode 会给我一个错误。但是,如果我callback像下面这样设置可选,则将结果保留 @escaping在 Xcode 错误中:

// This is wrong (Xcode complains about @escaping)
func someFunc(someArg: Int, callback: @escaping ((Error?) -> Void)?) {
    DispatchQueue.global(qos: .background).async {
    ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这是为什么?谢谢你!

Swe*_*per 4

如您所知,默认情况下,闭包参数无法转义。你必须添加@escaping才能让他们逃脱。请参阅此处了解闭包逃逸的含义。

更准确的措辞是,函数参数位置中的闭包默认情况下是非转义的。如您所知,((Error?) -> Void)?是 的语法糖Optional<(Error?) -> Void>。这里,闭包类型不在“函数参数位置”。它用作泛型类型的泛型参数Optional。这只是我的意见,但您不认为似乎将可选@escaping Optional<(Error?) -> Void> 标记为“转义”吗?

对于更极端的情况,元组怎么样?如何仅将一对闭包中的第一项标记为转义?另外,如果我有一个T<(Error?) -> Void>,是否保证它一定会存储闭包的实例?我的意思是,它只是一个通用类型:

class Foo<T> {}

let a: Foo<(Int) -> Int> = Foo()
Run Code Online (Sandbox Code Playgroud)

@escaping那么应该对这个结构做什么呢?

最后,包裹在一个Optional 已经逃逸的闭包中不是吗Optional

也许是因为需要设计、实现和测试的东西太多,Swift 团队只是在可选值和元组中进行了所有闭包,以及隐式转义的其他泛型类型。

另请参阅:SR-2444