与 Swift @escaping 的小故事

863 阅读1分钟

在半年前的一次面试中...

面试官:网络请求的 block 怎么写的?

我:func request(completion: (() -> Void)?)

面试官:不需要加 @escaping 吗?

我:不需要

面试官:为什么?

我:这个闭包是可选的

面试官:这是一个逃逸闭包,逃逸闭包要加 @escaping,和闭包是不是可选有什么关系?

我:不知道...

内心OS:我也不知道为什么...可我这么写没报错啊...

先说结论,以下两个方法都不会报错,接下来就来说说为什么第二个方法不会报错。

func request(completion: @escaping () -> Void) { }
func request(completion: (() -> Void)?) { }

首先我们要知道可选类型的本质是什么?可选类型的本质是一个枚举,声明如下。

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
}

所以第二个方法实际上是这样子的。

func request(completion: Optional<() -> Void>) { }

因为可选闭包本质是一个枚举,completion 参数传递的是一个枚举,所以不需要加上 @escaping