逃逸闭包(@escaping)和非逃逸闭包

逃逸闭包(@escaping)和非逃逸闭包

[toc]

今天学习GCD时,用闭包写了个函数出现了这些问题,如图
6455CAF8-20E8-4F70-B585-1CF2840BD5F5
问题报错:

1.Function types cannot have argument labels; use '_' before 'result'
2.Closure use of non-escaping parameter 'comletion' may allow it to escape
3.Closure use of non-escaping parameter 'comletion' may allow it to escape
4.Parameter 'comletion' is implicitly non-escaping
5.Extraneous argument label 'result:' in call

1.函数类型前不能有参数标签,需要用‘_’替换
2.闭包使用了非逃逸参数‘comletion’,需要让它逃逸
3.闭包使用了非逃逸参数‘comletion’,需要让它逃逸
4.参数‘completion’ 是隐式的非逃逸闭包
5.Extraneous argument label ‘result:’ in call

虽然我们可以根据这些提示,来修改错误代码

非逃逸闭包

非逃逸闭包:当函数执行过程中,执行的函数内部的闭包,叫做非逃逸闭包 @noescape
非逃逸闭包的生命周期:

把闭包作为参数传递给函数。
函数中运行该闭包。
退出函数。
1411204-b56b97c93063dbaa

如图,函数在运行完后,闭包并没有逃逸,而是被限制在函数中。

逃逸闭包

逃逸闭包:当函数执行结束后,才去调用函数内部的闭包,叫做逃逸闭包
逃逸闭包的生命周期:
逃逸闭包恰恰与非逃逸闭包相反,其生命周期长于相关函数,当函数退出的时候,逃逸闭包的引用仍然被其他对象持有,不会在相关函数结束后释放。(有点像OC中的strong哈)

1411204-065fc11c7ec14729

如上图所示,当函数结束的时候,闭包依然会在外面的世界里逍遥快活,对于内存管理来说这可不是好现象。

注意

而在3.0中,闭包参数默认是非逃逸类型,如果需要逃逸类型的闭包,记得使用关键字@escaping

而对于非逃逸型闭包,由于其生命周期确定短于相关函数,编译器可以据此做性能优化。

总结

要谨慎使用@escaping(逃逸闭包),除非明确知道要使用它做什么。

下面是使用逃逸闭包的2个场景:

异步调用: 如果需要调度队列中异步调用闭包, 这个队列会持有闭包的引用,至于什么时候调用闭包,或闭包什么时候运行结束都是不可预知的。
存储: 需要存储闭包作为属性,全局变量或其他类型做稍后使用。

-------------本文结束感谢您的阅读-------------