Swift闭包

闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。

闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。

闭包表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//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(<)

尾随闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
}

值捕获

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

闭包是引用类型

1
2
let alsoIncrementByTen = incrementTen
alsoIncrementByTen() // 50

非逃逸闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

自动闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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–