在我们的开发过程中,时常会使用到闭包,有的会用 @escaping 关键字修饰,有的则不会。今天,通过这篇文章希望能让大家对何时使用 @escaping,以及为什么使用有一个清晰的认知。
什么时候使用
当闭包的生命周期超过当前函数的生命周期
时,我们需要使用该关键字标识。
异步执行的闭包
比如下面的代码:
func doAsySomething(completion: @escaping () -> ()) {
print("begin - doAsySomething")
DispatchQueue.main.async {
completion()
}
print("end - doAsySomething")
}
doAsySomething {
print("doAsySomething")
}
// 打印结果:
begin - doAsySomething
end - doAsySomething
doAsySomething
通过上述的打印结果可以发现,虽然 doAsySomething
函数已经执行完,但是 completion 还未执行完,所以它的声明周期已经超过了 doAsySomething
函数的生命周期。因此,这里需要使用 @escaping
关键字标识。
如果不适用 @escaping 标识的话,编译器也会报错。
无法得知闭包何时执行
因为 completion 放在了数组中,而我们无法得知它什么时候会执行,所以也需要使用 @escaping
修饰。
var completions: [()->()]!
func doSomething(completion: @escaping () -> ()) {
completions.append(completion)
}
无须使用 @escaping
如果闭包的声明周期未超过当前函数的声明周期,则无须使用 @escaping
。比如下面的代码:
func doSomething(completion: () -> ()) {
print("begin")
completion()
print("end")
}
doSomething {
print("do something")
}
// 打印结果:
begin
do something
end
通过打印结果可以得知,闭包的声明周期是在 doSomething 函数之内的。所以不需要使用 @escaping
标识。
为什么使用
上面讲了 @escaping 的使用场景,这里讲一下为什么要使用 @escaping 关键字。有 OC 经验的同学都知道,在实现 block 的时候,需要时刻警惕循环引用的存在。而在 Swift 中,@escaping 正是为了避免大家的代码造成循环引用的问题而存在的。
在 @escaping 标识的闭包中,会强制你显式的使用 self,提醒你此处代码可能会造成循环引用,需要你小心编写此处代码,从而避免代码的出错率。
所以,为什么要使用 @escaping 呢?因为这样可以提醒大家避免代码出错的概率,从而提高代码的质量。
总结
- 同步执行的闭包
无须
@escaping 修饰;异步执行的闭包必须
使用 @escaping 修饰。 - 无法得知闭包何时执行,也需要使用 @escaping 修饰。
- 使用 @escaping 修饰的闭包,编译器会强制你显式的使用 self,从而避免代码出错的概率,从而提高代码质量。