谈谈Swift里面的闭包


闭包是Swift中很重要的一点,也是难点。学习了Swift很久,记录一下对闭包的思考。

理解

1、闭包可以讲是一段代码的集合与函数类似,也是引用类型。
2、闭包的使用:主要用与回调(异步回调等等)
3、闭包可以作为函数参数传递等。
4、闭包表达式风格简洁,官方鼓励在一些常见的场景中进行语法优化,虽然在一定程度上会降低代码的可读性。
5、Swift的语法非常适合函数式编程的使用,而闭包正是函数式编程的核心概念之一了。

语法

{ (parameters) -> return type in
    statements
}

闭包表达式参数 可以是 in-out 参数,但不能设定默认值。如果你命名了可变参数,也可以使用此可变参数。

几种类型

普通闭包
let closure = {(x:Int) -> Int in
    return x*x
}
尾随闭包
func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函数体部分
}

// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure(closure: {
    // 闭包主体部分
})

// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
    // 闭包主体部分
}

我们都知道闭包可以作为函数的参数,当我们最好一个参数为一个闭包表达式的时候,这个时候尾随闭包就出现了。
当一个闭包表达式很长,以至于不在一行编写的时候,尾随闭包就变得非常有用。
通过尾随闭包的语法,优雅地在函数后封装了闭包的具体功能,而不再需要将整个闭包包裹在 某个函数function(_ : ) 方法的括号内

逃逸闭包

当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,这类型的闭包会在函数中逃逸。一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
自动闭包

自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。简单来说 @autoclosure 做的事情就是把一句表达式自动地封装成一个闭包(closure),
自动闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。
自动闭包让你能够延迟求值,因为直到你调用这个闭包,代码段才会被执行。延迟求值对于那些有副作用和高计算成本的代码来说是很有益处的,因为它使得你能控制代码的执行时机。例如:

var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// 打印出“5”

let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// 打印出“5”

print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// 打印出“4”

这里联想到了系统 ?? 这个操作符,根据延迟求值的这个特性,猜测一下这个方法的具体实现。

func ??<T>(optional: T?, defaultValue: @autoclosure () -> T) -> T {
    switch optional {
    case .Some(let value): 
        return value
    case .None:
         return defaultValue()
}
    }

在我们需要返回的时候,一般思路是需要对optional进行求值,如果optinal不为nil的话,我们完全可以避免这个求值的计算,即将求值计算推迟到optional 判定为nil 之后。

值捕获

闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。

func makeAdd(addNum amount: Int) -> () -> Int {
    var total = 0
    func add() -> Int {
        total += amount
        return total
    }
    return add
}

let addTen = makeAdd(addNum: 10)
addTen() //10
addTen() // 20
let answer = addTen() 
print(answer) // 30
let addTenAnother = makeAdd(addNum: 10)
print(addTenAnother()) // 10

上面这段代码makeAdd函数返回的是一个 () -> Int 内嵌函数类型也就是闭包的一种类型,是一个引用类型,然后创建了一个addTen函数类型对象,这个对象内部对total这个变量进行了值捕获,当这个函数类型对象消亡时,Swift也会为我们进行total这类的变量回收。

随便聊聊闭包,来总结一下:闭包是Swift里面的一个特别重要的概念,因为它,让swift的代码更加优雅,笔者目前也正在努力学习着,期待着有一天能写出非常优雅的代码。


文章作者: Cone
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 Cone !
  目录