闭包是特殊的函数
Swift 中,闭包其实是一个特殊的函数,匿名函数
var block = {
print("3")
}
print(block)
输出
(Function)
闭包语法
{ (参数) -> 返回值类型 in
闭包实现
return 返回值
}
简写:
// 单行闭包 省略 return
let block1 = { (parm: Int) -> Int in parm + 1}
print(block1(3))
// 省略返回值类型 (单行多行闭包都可以)
let block2 = { (parm: Int) in parm + 1}
let block3 = { (parm: Int) in
return parm + 1
}
print(block3(2))
// 省略参数、返回值 in,直接用 $0 $1 来访问
let block4 = {
return $0 + 1
}
print(block4(5))
// 如果参数的类型已知(根据函数判断),可以省略参数类型以及括号
func tmpFunc(block: (Int) -> (Void)) {
let a = 10
block(a)
}
tmpFunc { p0 in
print("\(p0 + 1)")
}
简写规则:
-
如果是单行闭包,可以省略
return
-
如果已知返回值类型(根据函数类型推断),可以省略
返回值类型
-
如果已知参数类型,可以省略
参数类型
和参数的括号()
-
如果用
$0 $1...
来访问参数,可以省略参数
和int
简单来说,除了 大括号{}
和 函数体
之外,满足特定条件的话就都可以省略
尾随闭包
尾随闭包是特殊的闭包,即当在函数的最后一个参数是闭包的时候,那么这个闭包是尾随闭包
func theFunc(parm: Int, block: (Int) -> (Void)) {
}
上述函数的 block
是一个尾随闭包
特性:
- 在调用尾随闭包的时候,可以将闭包写到参数括号外面:
theFunc(parm: 3) { (par) -> (Void) in
}
这样可以增强可读性
- 当函数只有一个闭包作为参数的时候,调用的时候可以省略
括号()
func theFunc2(block: (Int) -> (Void)) {
}
theFunc2 { (par) -> (Void) in
}
逃逸闭包
闭包作为参数传递给函数的时候,其作用域为函数内部,即当函数返回的时候,该闭包就释放了,如果想在函数返回之后还能执行,需要使用逃逸闭包。
如果不显式指明闭包是逃逸闭包,则 默认是非逃逸(non-escaping) 闭包。显式指明为逃逸闭包需要在参数中增加 @escaping
关键字:
func func0(block: @escaping () -> ()) {
}
函数 func0 接受的 block 是一个逃逸闭包,作用域不仅限于函数内
通常用于需要保存闭包的场景:
var blocks:[() -> ()] = [() -> ()]()
func saveBlock(block: @escaping () -> ()) {
blocks.append(block)
}
// 保存 block
saveBlock {
print("hello")
}
// 在 saveBlock 方法返回后才执行到这儿
let block = blocks[0]
block()
输出:
hello
上述代码和输出表明,逃逸闭包的作用域不仅限于函数中。
自动闭包
自动闭包能将是普通闭包的一种,主要的区别的在声明的时候不需要声明参数,在调用的时候传入参数,并且由 Swift 自动将参数封装成带参数的闭包
这一种闭包需要在闭包前加上关键字 @autoclosure
,如下:
func tmpFunc(isSuc: Bool, block: @autoclosure ()->(Bool)) {
if (isSuc) {
block()
}
}
该函数的 block
参数就是一个自动闭包,在传参的时候仅需要传入一个 返回值为 Bool 的表达式即可,如下:
tmpFunc(isSuc: false, block: 2>3)
思考:为什么需要自动闭包?(自动闭包的使用场景)
主要是为了节省开销,实际上,在 tmpFunc
的声明时候,我们声明其第二个参数是一个 Bool
类型而无需是一个闭包也能很好地工作。但是假如后面的表达式需要耗费大量的时间去计算的话,且第一个参数为 false
,就会造成不必要的开销,因为我们根本无需计算第二个参数的值。
可以看出使用闭包可以省去不必要的提前计算。
func tmpFunc(isSuc: Bool, block: @autoclosure ()->(Bool)) {
if (isSuc) {
if (block()) {
print("a")
}
}
}
func tmpFunc2(isSuc: Bool, block: Bool) {
if (isSuc) {
if (block) {
print("b")
}
}
}
tmpFunc(isSuc: false, block: 2>3 && 2>3 && 2>3 && 2>3 && 2>3 && 2>3)
tmpFunc2(isSuc: false, block: 2>3 && 2>3 && 2>3 && 2>3 && 2>3 && 2>3)
tmpFunc
仅在 isSuc
为 true
的时候会调用 2>3 && 2>3 && 2>3 && 2>3 && 2>3 && 2>3
这个复杂表达式,而 tmpFunc2
无论 isSuc
为何值都会调用那个复杂的表达式,造成了不必要的复杂计算。
网友评论