闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。
闭包表达式
//sort方法
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
//普通函数
func backwards(s1: String, s2: String) -> Bool {
return s1 < s2
}
var reversed = names.sort(backwards)
//闭包表达式语法
reversed = names.sort({(s1: String, s2: String) -> Bool in
return s1 < s2
})
//根据上下文推断类型
reversed = names.sort({s1, s2 in return s1 < s2})
//单表达式闭包隐式返回
reversed = names.sort({s1, s2 in s1 < s2})
//参数名称缩写
reversed = names.sort({$0 < $1})
//运算符函数
reversed = names.sort(<)
尾随闭包
func someFunctionThatTakesAClosure(closure: () -> Void) {
//函数体部分
}
//以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
//闭包主体部分
})
//以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure(){
//函数主体部分
}
reversed = names.sort(){$0 < $1} //闭包表达式
reversed = names.sort{$0 < $1} //如果函数表达式只需要一个参数,使用尾随闭包是,可以将 () 省略
//尾随闭包举例
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
(number) -> String in
var number = number
var output = ""
while number > 0 {
output += digitNames[number % 10]!
number /= 10
}
return output
}
值捕获
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
let incrementTen = makeIncrementor(forIncrement: 10)
incrementTen() // 10
incrementTen() // 20
incrementTen() // 30
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven() // 7
incrementTen() // 40
闭包是引用类型
let alsoIncrementByTen = incrementTen
alsoIncrementByTen() // 50
非逃逸闭包
func someFunctionWithNoescapeClosure(@noescape closure: () -> Void){
closure()
}
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: () -> Void) { //这个时候如果把completionHandler参数标注为 @noescape 会获得一个编译错误
completionHandlers.append(completionHandler)
}
//将闭包标注为 @noescape 能是你在闭包中饮食调用self
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure{ self.x = 100 }
someFunctionWithNoescapeClosure{ x = 200 }
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x) // 200
completionHandlers.first?()
print(instance.x) // 100
自动闭包
var customsInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customsInLine.count) // 5
//赋值给一个变量或者常量,实现延时求值
let customerProvider = { customsInLine.removeAtIndex(0) } //只定义,没执行
print(customsInLine.count) // 5
print("No serving \(customerProvider()) !") // prints "Now serving Chris!"
print(customsInLine.count) // prints "4"
//作为函数的参数,实现延时求值
func serverCustomer(customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serverCustomer({ customsInLine.removeAtIndex(0) }) //prints "Now serving Alex"
func serveCustomer(@autoclosure customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serveCustomer(customsInLine.removeAtIndex(0))
//@autoclosure特性暗含了@noescape特性,这个特性在非逃逸闭包一节中有描述。如果你想让这个闭包可以“逃逸”,则应该使用@autoclosure(escaping)特性.
var customerProviders: [() -> String] = []
func collectCustomerProviders(@autoclosure(escaping) customerProvider: () -> String) {
customerProviders.append(customerProvider)
}
print("**Collected \(customerProviders.count) closures.")
collectCustomerProviders(customsInLine.removeAtIndex(0))
collectCustomerProviders(customsInLine.removeAtIndex(0))
print("Collected \(customerProviders.count) closures.")
for customerProvider in customerProviders {
print("Now serving \(customerProvider())")
}
--EOF--