当闭包作为一个实际参数传递给一个函数的时候,并且它会在函数返回之后调用我们就说这个闭包逃逸了,当你声明一个接受闭包作为形式参数的函数时,你可以在形式参数前写@escaping来明确闭包是允许逃逸的。
闭包可以逃逸的一种方法是被存储在定义与函数外的变量里,比如说,很多函数接受闭包实际参数来作为启动异步任务的回调。函数在启动任务后返回,但是闭包要直到任务完成--闭包需要逃逸,以便于稍后调用
//: A UIKit based Playground for presenting user interface
import UIKit
var completionHansdlsers:[()-> Void] = []
func someFuntionWIthEscapingClosure(completionHandler:@escaping ()->Void){
completionHansdlsers.append(completionHandler)
}
让闭包@escaping 意味着你必须在闭包中显示地引用self
//: A UIKit based Playground for presenting user interface
import UIKit
var completionHansdlsers:[()-> Void] = []
func someFuntionWIthEscapingClosure(completionHandler:@escaping ()->Void){
completionHansdlsers.append(completionHandler)
}
func someFuntionWithNoneScapingClosure(closure:()->Void){
closure()
}
class SomeClass{
var x = 10
func doSomething(){
someFuntionWIthEscapingClosure {
self.x=100
}
someFuntionWithNoneScapingClosure {
x=200
}
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
//200
completionHansdlsers.first?()
print(instance.x)
//100
自动闭包
自动闭包是一种自动创建的用来把作为实际参数传递给函数的表达式打包的闭包。它不接受任何实际参数,并且当它被调用时,它会返回内部打包的表达式的值
这个语法的好处在于通过写普通表达式代替显示闭包而使你省略保卫函数形式参数的括号
下面代码不能执行。。。是系统的源码
autoclosure 就是自动闭包
//: A UIKit based Playground for presenting user interface
import UIKit
public func assret(_ condition:@autoclosure() -> Bool,_ message:@autoclosure() -> String = String(),file:StaticString=#file ,line:UInt = #line
let number = 3
assert(number > 3,"number不大于3")
自动闭包允许你延迟处理,因此闭包内部的代码直到你调用它的时候才会运行,对于有副作用或者占用资源的代码来说很有作用。
因为它可以允许你控制代码何时才进行求值
//: A UIKit based Playground for presenting user interface
import UIKit
var customersInLine = ["Chris","Alex","Ewa","Barry","Daniella"]
//54 06:03
print(customersInLine.count)
//相当于没有执行
let customProvider = {customersInLine.remove(at: 0)}
print(customersInLine.count)
//调用闭包表达式的时候才真正执行
print("Now serving \(customProvider())!")
print(customersInLine.count)
当你传一个闭包作为实际参数到函数的时候,你会得到与延迟处理相同的行为。
//: A UIKit based Playground for presenting user interface
import UIKit
var customersInLine = ["Chris","Alex","Ewa","Barry","Daniella"]
//相当于没有执行
let customProvider = {customersInLine.remove(at: 0)}
func serve(custom customerProvider:() ->String){
print("Now serving\(customerProvider())!")
}
serve(custom: {customersInLine.remove(at: 0)})
自动闭包
通过@autoclosure标志标记它的形式参数使用了自动闭包,现在你可以调用函数就像它接受了一个Sting 实际参数而不是闭包。实际参数自动地转换为闭包,因为customerProvider形式参数的类型被标记为 @autocloseure 标记
//: A UIKit based Playground for presenting user interface
import UIKit
var customersInLine = ["Chris","Alex","Ewa","Barry","Daniella"]
//相当于没有执行
let customProvider = {customersInLine.remove(at: 0)}
func serve(custom customerProvider:@autoclosure() ->String){
print("Now serving \(customerProvider())!")
}
serve(custom: customersInLine.remove(at: 0))
自动+逃逸
如果你想要自动闭包允许逃逸,就同时使用@autoclosure 和@escaping标志
//: A UIKit based Playground for presenting user interface
import UIKit
var customersInLine = ["Chris","Alex","Ewa","Barry","Daniella"]
var customerProviders:[()->String]=[]
func collectCustomerProviders(_ customerProvider:@autoclosure @escaping()->String){
customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))
print("Collecte d\(customerProviders.count) closures")
//prings "Collected 2 closures"
for customerProvider in customerProviders{
print("Now serving \(customerProvider())!")
}
Collecte d2 closures
Now serving Chris!
Now serving Alex!