引言:闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数(Lambdas)比较相似。一般用于入参为函数类型的函数
1.定义: 闭包的一般表达式为:
{ (parameters) -> return type in
statements
}
解析:parameters为入参、return type为返回值类型、statements为函数内部运行方法
例:数组有排序方法:sorted(by:),它会它会基于你提供的排序闭包表达式的判断结果对数组中的值(类型确定)进行排序
let list = ["Boy","God","Apple","Eye"]
let array = list.sorted(by:{(s1:String,s2:String)-> Bool in
return s1 > s2
})
print(array)
输出为:["God", "Eye", "Boy", "Apple"]
解析:在自己书写list的排序代码函数时,swift会自动联想出以下代码:
list.sorted(by:(String, String) throws -> Bool),这里我们可以发现函数内会有两个入参,要求返回Bool值,故我们在书写闭包函数时也是按此要求进行书写
2.在实际运用过程中,swift鼓励我们对闭包语法书写进行优化,主要优化点在于:
1.利用上下文,捕获入参的类型,省略入参类型书写,如上一个例子可以写成:
let list = ["Boy","God","Apple","Eye"]
let array = list.sorted(by:{(s1,s2)-> Bool in
return s1 > s2
})
print(array)
输出为:["God", "Eye", "Boy", "Apple"]
解析:因为list内的元素统一为String类型,所以list的排序方法内的闭包函数入参只能是String类型,那么我们在书写时即可将参数类型省略
2.隐式返回单表达式闭包,即单表达式闭包可以省略 return 关键字,如上一个例子可以写成:
let list = ["Boy","God","Apple","Eye"]
let array = list.sorted(by:{(s1,s2) in s1>s2})
print(array)
输出为:["God", "Eye", "Boy", "Apple"]
解析:由于排序方法里名称必须返回Bool值,且闭包表达式内只有一个单行的:s1>s2,已明确返回Bool值,故此时可以省略return关键字,且可以单行书写
3.参数缩写:swift自动为内联闭包提供了参数名称缩写功能,你可以直接通过 $0,$1,$2 来顺序调用闭包的参数,以此类推,且如果你在函数内使用参数缩写,关键字in也可以省略,故上一个例子可以写成:
let list = ["Boy","God","Apple","Eye"]
let array = list.sorted(by:{$0 < $1})
print(array)
输出为:["Apple", "Boy", "Eye", "God"]
4.尾随闭包:如果调用某个函数时需要将一个很长的闭包表达式当做该函数的最后一个入参传入时,那么此时你可以使用尾随闭包
定义:尾随闭包是一个书写在函数圆括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签,如上一个例子可以写成:
let list = ["Boy","God","Apple","Eye"]
let array = list.sorted(){$0>$1}
print(array)
输出为:["God", "Eye", "Boy", "Apple"]
**注意:如果闭包为该调用函数的唯一入参时,可以省略调用函数的(),如:**
输出为:["God", "Eye", "Boy", "Apple"]
let array = list.sorted{$0>$1}
输出为:["God", "Eye", "Boy", "Apple"]
3.闭包有两种特殊的类型:逃逸闭包和自动闭包
逃逸闭包,顾名思义为闭包想要逃离,即在闭包的载体函数执行完毕后,闭包还未进行执行,即可逃离,常用于异步操作,如:
定义:当闭包作为参数传入函数时,可在闭包前缀@escaping,意味着该闭包可以逃离该函数,如模拟网络请求:
func getData(block:@escaping (_ data:String)->Void) -> Void {
DispatchQueue.main.asyncAfter(deadline: .now()+3) {
block("数据")
}
}
调用:getData{print($0)}
print("下一步")
输出为:下一步 --间隔三秒-- 数据
解析:函数getData入参为闭包,且已前缀标注@escaping,意味该闭包可以逃逸,执行时传入闭包(捕获入参类型,隐式返回、参数缩写、尾随闭包均已运用),在函数执行完毕时,主线程内接着执行下个任务(打印"下一步"),3秒后执行闭包内的代码
注意:1.@escaping仅用于函数类型之前
2.从Swift3.0开始, 苹果官方建议方法中函数类型的参数不要带参数名称, 尤其是不能带外部参数名.故忽略参数标签,否则会报错
自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。这种便利语法让你能够省略闭包的花括号{},用一个普通的表达式来代替显式的闭包。
定义:当闭包作为参数传入函数时,可在闭包前缀@autoclosure,如:
func creatView(view:@autoclosure()->String){
print(view())
}
调用:creatView(view: "好美"),输出:好美