class MyClass {
var completionHandler: (() -> Void)?
func foo(_ escapingClosure: @escaping () -> Void) {
//if you don't mark as @escaping you get
//Assigning non-escaping parameter 'escapingClosure' to an @escaping closure
completionHandler = escapingClosure //<- error here
}
func onEvent() {
completionHandler?()
}
}
completion是completionHandlerAbout,如果您想突出显示它是@escaping,则可以使用completionHandler命名 一个三个三个一个 Sync vs Async(https://stackoverflow.com/a/75225609/4770877) Java functional interfaces(https://stackoverflow.com/a/61232621/4770877)
8条答案
按热度按时间wnvonmuf1#
请看这个类:
someMethod
将传入的闭包赋给类中的属性。现在又来了一堂课:
如果我调用
anotherMethod
,闭包{ self.number = 10 }
将被存储在A
的示例中,因为self
是在闭包中捕获的,所以A
的示例也将持有对它的强引用。这基本上就是一个转义闭包的例子!
你可能想知道,“什么?那么封闭从哪里逃出来,逃到哪里去了?”
闭包从方法的作用域逃逸到类的作用域。并且它可以在以后调用,甚至在另一个线程上调用!如果处理不当,这可能会导致问题。
默认情况下,Swift不允许闭包转义,你必须在闭包类型中添加
@escaping
来告诉编译器“请允许这个闭包转义”。如果我们删除@escaping
:并尝试编写
self.closure = closure
,它无法编译!7cjasjjr2#
我将用一种更简单的方式。
请看这个例子:
以上是一个非转义闭包,因为闭包是在方法返回之前调用的。
考虑具有异步操作的相同示例:
上面的示例包含一个转义闭包,因为闭包调用可能发生在函数由于异步操作而返回之后。
在上面的例子中,你可以很容易地意识到闭包是在函数体之外移动的,所以它需要是一个转义闭包。
nonescaping
闭包的优点。*gab6jxml3#
I find this website very helpful on that matter简单解释如下:
如果闭包作为参数传递给函数,并且在函数返回后被调用,则闭包将转义。
阅读更多的链接,我通过以上!:)
fxnxkyjh4#
默认情况下,闭包是非转义的。为了便于理解,你可以把非转义闭包看作局部闭包(就像局部变量一样),把转义闭包看作全局闭包(就像全局变量一样)。这意味着一旦我们从方法体中出来,非转义闭包的作用域就丢失了。但是在转义闭包的情况下,内存将闭包保留在内存中。
***简单地说,当我们在方法中的任何异步任务内调用闭包时,或者在调用闭包之前方法返回时,我们使用转义闭包。
因为它是非转义闭包,一旦我们从"add"方法中出来,它的作用域将丢失。completion(num1 + num2)将永远不会调用。
即使方法返回(即我们离开方法作用域),闭包也会被调用。
enter code here
vxbzzdmp5#
斯威夫特4.1
来自语言参考:Swift编程语言的属性(Swift 4.1)
苹果清楚地解释了
escaping
属性。将此特性应用于方法或函数声明中的参数类型,以指示可以存储该参数的值以供以后执行。这意味着允许该值在调用的生存期之后继续存在。具有转义类型特性的函数类型参数要求对属性或方法显式使用self.。有关如何使用转义特性的示例,请参见Escaping Closures
someFunctionWithEscapingClosure(_:)
函数将闭包作为参数,并将其添加到在函数外部声明的数组中。如果不使用@escaping
标记此函数的参数,则会出现编译时错误。当闭包作为参数传递给函数,但在函数返回后被调用时,闭包被称为转义函数。当声明一个将闭包作为其参数之一的函数时,可以在参数类型之前写入@escaping,以指示允许该闭包转义。
pbwdgjma6#
逃逸的定义
Swift的闭包是引用类型,这意味着如果你将两个变量指向同一个闭包,它们共享这个闭包-- Swift只需通过增加引用计数来记住有两个东西依赖于它。
当一个闭包被传递给一个函数使用时,Swift需要知道这个函数是否会被立即使用,或者是否会被保存以供以后使用。编译器可以跳过对引用计数加1,因为闭包会被直接运行,然后被遗忘,但是如果它被稍后使用--或者甚至可能被稍后使用--Swift需要给它的引用计数加一,这样它就不会意外地被销毁。
快速示例
转义闭包的一个很好的例子是完成处理程序,它在将来执行,当一个冗长的任务完成时,所以它的寿命比创建它的函数的寿命长。另一个例子是异步编程:异步执行的闭包总是会脱离它的初始上下文。
附加信息
由于性能原因,Swift假设所有闭包都是非转义闭包,这意味着它们将在函数内部立即使用,而不会被存储,这反过来意味着Swift不触及引用计数,如果不是这样--如果你采取任何措施来存储闭包--Swift将强制你将其标记为@escaping,这样引用计数就必须改变。
8hhllhi27#
Function and closure(https://stackoverflow.com/a/60988242/4770877)
一个月一个月
@noescape
是传递给函数的闭包,在函数返回之前调用non-escaping closure
的一个很好的例子是Array
sort function
-sorted(by: (Element, Element) -> Bool)
。这个闭包在执行排序计算时被调用。历史记录:
@noescape
在Swift 2
中被引入-〉在Swift 3
中被弃用,成为默认值,这就是为什么您应该显式标记@escaping
属性。escaping closure
转义闭包(引用)在方法结束时仍处于活动状态。
@escaping
是一个闭包,1.传入函数
1.在所有者函数返回**之后调用闭包(使用属性)(异步)
异步操作中的
completion handler
就是escaping closure
的一个很好的示例。在这种情况下,如果不使用@escaping
标记函数,则会出现编译时错误。引用escaping closure
中的属性要求显式使用self
completion
是completionHandler
About,如果您想突出显示它是@escaping,则可以使用completionHandler
命名一个三个三个一个
Sync vs Async(https://stackoverflow.com/a/75225609/4770877)
Java functional interfaces(https://stackoverflow.com/a/61232621/4770877)
6qftjkof8#
下面是转义和无转义闭包的简单示例。