Swift(四) 闭包

闭包

表达式

{(params) -> returnType in statements}

Sort 方法

见 Xcode

尾随闭包

尾随闭包 - 是一个书写在函数括号之后的闭包表达式 如果只需要一个闭包参数 可以将 () 省略

1
2
3
4
5
6
7
8
9
10
11
12
13
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体部分
}

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

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

非逃逸闭包(Nonescaping Closures)

当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。

当你定义接受闭包作为参数的函数时,你可以在参数名之前标注@noescape,用来指明这个闭包是不允许“逃逸”出这个函数的。

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
func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
closure()
}

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: () -> Void) {
completionHandlers.append(completionHandler)
}

class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 }

// 使用 @noescape 使你能在闭包中隐式地引用self
someFunctionWithNoescapeClosure { x = 200 }
}
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)
// prints "200"

completionHandlers.first?()
print(instance.x)

自动闭包(Autoclosures)

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

自动闭包暗含了@noescape特性,如果你想让这个闭包可以“逃逸”,则应该使用@autoclosure(escaping)特性.

1
2
3
4
5
6
7
8
9
10
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serveCustomer(@autoclosure customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
// (自动闭包)调用方法
serveCustomer(customersInLine.removeAtIndex(0))
// prints "Now serving Ewa!"

// (正常)调用方法
serveCustomer( { customersInLine.removeAtIndex(0) } )

捕获值

闭包中对任何其他元素的引用都是会被闭包自动持有的

为了优化,如果一个值是不可变的,Swift 可能会改为捕获并保存一份对值的拷贝。

Swift 也会负责被捕获变量的所有内存管理工作,包括释放不再需要的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

func makeIncrementor(forIncrement amount: Int) -> () -> Int {

var runningTotal = 0

// 嵌套函数是最简单的闭包形式
func incrementor() -> Int {

// 在嵌套函数中可以使用外部函数的变量 是因为捕捉了变量的引用
runningTotal += amount

return runningTotal
}

return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)
//runningTotal 变量的作用域已经消失,但是返回值还在增加
print(incrementByTen())
print(incrementByTen())

循环引用

weak

当所引用的对象被释放后,被标记为weak的变量会自动变成nil (被标记为@weak 的变量一定需要是Optional值)

unowned

设置以后即使它原来引用的内容已经被释放了,它仍然会保持对被已经释放了的对象的一个 “无效的” 引用,它不能是 Optional 值

见Xcode