【Swift】闭包(Closure)

2022-12-24  本文已影响0人  小雪球大梦想

闭包定义

//函数定义
func name(parameters) -> return type {
    function body
}

//闭包定义
{ (parameters) -> return type in
    statements
}

从上面的函数和闭包的定义中可以看到(parameters) -> return type是相同的,都是传入参数,可对参数进行操作,然后返回一个值。从定义中可以看出,函数是有name的,而闭包没有。

那么闭包是如何调用的呢?

//函数
func area(_ width: Double, _ height: Double) -> Double {
    return width * height
}
print(area(3, 4))//打印12.0

//闭包
let closureArea = { (width: Double, height: Double) -> Double in
    width * height//单行表达式,因为只有一行表达式,所以return可以不写
}
print(closureArea(3, 4))//打印12.0

函数中给这个求面积的函数命名为area,而闭包是用{}包裹起来,在这里闭包是没有名字的,所以将闭包赋值相当于给闭包一个名字closureArea,这样闭包就能像函数一样使用。所以area约等于closureArea

闭包是特殊的函数,当函数作为参数,或返回值,或匿名函数时,称为闭包。

// 为参数,(Double, Double) -> Double为闭包
func area(handle: (Double, Double) -> Double) -> Double {
    return handle(3, 4)
}
print(area(handle: {$0 * $1}))//打印12.0

area函数看到,函数中只传入一个闭包,然后返回一个Double值。函数返回值是执行闭包返回的结果,闭包传入(3, 4)

闭包对参数做了什么?在调用area函数时,需要将闭包传入,这里是传入{$0 * $1}闭包,对参数执行乘法运算。

// 为返回值
func area() -> (Double, Double) -> Double {
    return { $0 * $1 }
}
print(area()(3, 4))//打印12.0

area函数看到,函数中没有传入参数,只有返回一个闭包(Double, Double) -> Double,闭包执行了第一个和第二个参数的乘法运算,所以area()就是一个闭包。

(3, 4)是闭包传入的参数,所以结果为12.0

// 为匿名函数
let areaValue = { (width: Double, height: Double) -> Double in
    return width * height
}(3, 4)
print(areaValue)//打印12.0

{ (width: Double, height: Double) -> Double in return width * height }是一个闭包,这里我们没有把闭包赋值给一个对象,而是直接使用闭包。直接将(3, 4)传入闭包,所以这个闭包是一个没有名字的闭包,称匿名闭包。

最简闭包

单行表达式,隐式返回值,return可以不写。

简化参数

$0$1,代表第01个参数。

// 闭包
{ (width: Double, height: Double) -> Double in
    return width * height
}

// 最简闭包,简化参数
{ $0 * $1 }

尾随闭包

闭包是函数的最后一个参数,称为尾随闭包。

func area(width: Double, height: Double ,handle: (Double, Double) -> Double) -> Double {
    return handle(width, height)
}
print(area(width: 3, height: 4, handle: {$0 * $1}))//打印12.0

area函数中可以看到,函数中有widthheight(Double, Double) -> Double三个参数,返回一个Double值。

从函数中的handle(width, height)中,我们可以看到widthheight作为参数传到handle这个闭包里面,闭包根据传值做了一个处理然后返回一个Double值,具体要对widthheight做什么处理,需要将闭包作为参数传入area函数中进行处理。

在例子中,传入了闭包{$0 * $1},这个闭包的意思是对传入的第一个和第二个参数做乘法运算,所以打印的结果就是3 * 4,计算结果12.0

//尾随闭包写法
let value1 = area(width: 3, height: 4, handle: {$0 * $1})
// 简化
let value2 = area(width: 3, height: 4) { $0 * $1 }
print(value1, value2)//打印12.0 12.0

自动闭包

自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。
这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。
这种便利语法让你能够省略闭包的花括号{},用一个普通的表达式来代替显式的闭包。

// 闭包
func closure(_ closure: () -> String) {
    print("closure \(closure())")
}

closure({ "value1!" })
closure { "value2!" }

// 自动闭包
func autoClosure(_ closure: @autoclosure () -> String) {
    print("autoClosure \(closure())")
}

autoClosure("v3!")

逃逸闭包

一个接受闭包作为参数的函数,该闭包可能在函数返回后才被调用,也就是说这个闭包逃离了函数的作用域,这种闭包称为逃逸闭包。当你声明一个接受闭包作为形式参数的函数时,你可以在形式参数前写@escaping来明确闭包式允许逃逸,并且在闭包中显式地引用self

逃逸闭包的生命周期

  1. 闭包作为参数传入函数。
  2. 退出函数。
  3. 闭包被调用,闭包生命周期结束。

逃逸闭包的生命周期比函数长,函数退出时,逃逸闭包的引用仍被其他对象持有,不会在函数结束时释放。

var array: Array<() -> String> = []

func appendClosure(_ closure: @autoclosure @escaping () -> String) {
    array.append(closure)
}

appendClosure("Hello")
let closure = array.first!
print(closure())// 打印 Hello

appendClosure函数看出,() -> String闭包传入到appendClosure函数中,函数引用了闭包,并将闭包保存到了数组中。退出函数后,闭包还没被调用,所以这个时候闭包就逃逸了。

上一篇下一篇

猜你喜欢

热点阅读