Swift Closures | Swift 闭包

更新至Swift 3.0

基本语法

Closures 在 Swift 中的概念类似 C 和 Objective-C 中的 blocks 和其它语言中的 lambdas.

{ (参数) -> return type in
    表达式
}

举例:排序以下字符串数组

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

普通方法调用

func backwards(s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sort(backwards)  // 系统提供的sort方法
// reversed 等于 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

将自定义 backwards 方法作为参数传入 sort(_:) 方法用于排序


闭包调用

reversed = names.sort({ (s1: String, s2: String) -> Bool in
    return s1 > s2
})
  • 闭包写法和普通方法的区别
  • 可以去掉 func 声明 和方法名, 将之后内容用 { } 包起来
  • 由于参数后的 { 通过上步骤挪到前面去了, in 这个关键字可表示闭包内容的开始
  • 其它照旧,这么短的方法可写成一行,简洁

根据 names 的 string 内容,和 sort 方法声明需要的参数
系统可自动推导出这个闭包的参数类型,所以可不写参数类型

reversed = names.sort( { s1, s2 in return s1 > s2 } )

闭包会把单行表达式的结果隐式 return 所以 return 也可以不用写

reversed = names.sort( { s1, s2 in s1 > s2 } )

Swift 提供了参数名的缩写,按顺序分配分别为 $0,$1,$2 以此类推

reversed = names.sort( { $0 > $1 } )

Swift 做了一些工作让代码可以使用 Operator Functions 让代码变的更简单

reversed = names.sort( { > } )

Trailing Closures | 尾随闭包

如果闭包作为参数传递给方法时,在最后一位,它允许被写在 ( ) 外面

reversed = names.sort() { $0 > $1 }

要是这方法只有这么一个闭包参数,那连括号都可以省掉了

reversed = names.sort { $0 > $1 }

其存在的意义是让代码更简洁,可读性更好


Capturing Values | 捕获数值

一个闭包可以获取在它周围上下文定义的常量或变量,哪怕这参数不存在了也依然可以

闭包属于引用类型,把闭包返回给一个对象时,如果闭包内有通过引用该对象,去方法其属性变量之类的操作,就会产生相互引用。从而导致的循环引用,会使内存无法释放


Nonescaping Closures | 非逃逸闭包

当一个闭包被当做参数传递给一个方法时,而且它会在这个方法返回后被调用,那它就算是个逃逸闭包

对于非逃逸的闭包,可以在闭包参数前声明关键字 @noescape 来告诉编译器,于是编译器就会做更多更激进的优化

func someFunctionWithNonescapingClosure(closure: @noescape () -> Void) {
    closure()
}

Autoclosures | 自动闭包

当我们把一个闭包作为参数传递的时候,这个闭包有一对醒目的花括号来表示它是个闭包。哪怕它只有一行表达式

// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serveCustomer(customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
}
serveCustomer( { customersInLine.removeAtIndex(0) } )
// Prints "Now serving Alex!”

自动动闭包会把传递给函数的表达式包自动装成闭包,这样就不用每次都写一对 {} 了,只要在参数前声明 @autoclosure 关键字即可,但是这个闭包不接受任何参数,只计算闭包内的内容

// customersInLine is ["Ewa", "Barry", "Daniella"]
func serveCustomer(@autoclosure customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
}
serveCustomer(customersInLine.removeAtIndex(0))
// Prints "Now serving Ewa!”

自动闭包隐式的就是个非逃逸闭包,如果要传递的是逃逸闭包,需要加上声明 @autoclosure(escaping) 即可


参考

  1. The Swift Programming Language (Swift 3.0) | Closures
  2. Autoclosures

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