Swift 闭包

闭包是特殊的函数

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 仅在 isSuctrue 的时候会调用 2>3 && 2>3 && 2>3 && 2>3 && 2>3 && 2>3 这个复杂表达式,而 tmpFunc2 无论 isSuc 为何值都会调用那个复杂的表达式,造成了不必要的复杂计算。

你可能感兴趣的:(Swift 闭包)