Swift學習筆記之閉包
簡介 (真的很簡)
閉包的完整形態是這個樣子的:
{ (parameters) -> returnType in
statements
}
寫在一行裏就是這樣:
{(parameters) -> (returnType) in statements}
形式
閉包以三種形式存在:
1.全局的函數都是閉包,它們有自己的名字,但是沒有捕獲任何值。
2.內嵌的函數都是閉包,它們有自己的名字,而且從包含他們的函數裏捕獲值。
3.閉包表達式都是閉包,它們沒有自己的名字,通過輕量級的語法定義並且可以從上下文中捕獲值。
捕獲值
閉包可以捕獲上下文的值,然後把它存儲下來。至於存儲的是引用還是拷貝,Swift 會決定捕獲引用還是拷貝值,也會處理變量的內存管理操作。
下面這個例子可以說明很多問題:
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen() // runningTotal = 10
incrementByTen() // runningTotal = 20
incrementByTen() // runningTotal = 30
let incrementByTen2 = makeIncrementor(forIncrement: 10)
incrementByTen2() // runningTotal = 10
let incrementByTen3 = incrementByTen
incrementByTen() // runningTotal = 40
因為 incrementByTen2
聲明了一個全新的閉包,所以 runningTotal
並沒有繼續接著上面的計數。而 incrementByTen3
和 incrementByTen
指向的是同一個閉包,所以 runningTotal
的值是累加的。
參數縮寫
我們可以直接用 $0 $1 $2
這種來依次定義閉包的參數。比如 sorted
函數:
var reversed = sorted(["c","a","d","b"], { $0 > $1 }) // d c b a
尾隨閉包
我一直覺得閉包最後這個 })
很難看,在 JS 中隨處可見這種情況。如果閉包是函數的最後一個參數,Swift 提供了尾隨閉包 (Trailing Closures) 解決這個審美問題:
// 以下是不使用尾隨閉包進行函數調用
someFunc({
// 閉包主體部分
})
// 以下是使用尾隨閉包進行函數調用
someFunc() {
// 閉包主體部分
}
OK那麽前面那個排序的可以用尾隨閉包這麽改寫:
var reversed = sorted(["c","a","d","b"]) { $0 > $1 } // d c b a
如果除了閉包沒有其他參數了,甚至可以把小括號也去掉。
還記得我們前面寫的 map
、 reduce
、 filter
三元大將嗎?用尾隨閉包可以讓它們變得更好看。比如前面那個選出大於30的數字的 filter
就可以這樣寫:
var oldArray = [10,20,45,32]
var filteredArray = oldArray.filter{
return $0 > 30
}
println(filteredArray) // [45, 32]
變形
變形金剛神馬的最有愛了。總結一下 closure
的變形大致有以下幾種形態:
[1, 2, 3].map( { (i: Int) ->Int in return i * 2 } )
[1, 2, 3].map( { i in return i * 2 } )
[1, 2, 3].map( { i in i * 2 } )
[1, 2, 3].map( { $0 * 2 } )
[1, 2, 3].map() { $0 * 2 }
[1, 2, 3].map { $0 * 2 }
對比
通過 UIView 的 animateWithDuration
方法對 block 和 closure 進行簡單的對比。
block 版本:
[UIView animateWithDuration:1 animations:^{
// DO SOMETHING
} completion:^(BOOL finished) {
NSLog(@"OVER");
}];
closure 版本:
UIView.animateWithDuration(1, animations: { () in
// DO SOMETHING
}, completion:{(Bool) in
println("OVER")
})
可以看到原來的 ^
符號已經不復存在,取而代之的是加在參數和返回值後面的 in
。註意,如果有 in
的話,就算沒有參數沒有返回值也一定需要 ()
,否則會報錯。
總結
和 Objective-C 的 FuckingBlock 一樣,Swift 出來之後 FuckingClosure 也就應運而生。總結了 Closure 的常用語法和格式:
// 作為變量
var closureName: (parameterTypes) -> (returnType)
// 作為可選類型的變量
var closureName: ((parameterTypes) -> (returnType))?
// 做為一個別名
typealias closureType = (parameterTypes) -> (returnType)
// 作為函數的參數
func({(parameterTypes) -> (returnType) in statements})
// 作為函數的參數
array.sort({ (item1: Int, item2: Int) -> Bool in return item1 < item2 })
// 作為函數的參數 - 隱含參數類型
array.sort({ (item1, item2) -> Bool in return item1 < item2 })
// 作為函數的參數 - 隱含返回類型
array.sort({ (item1, item2) in return item1 < item2 })
// 作為函數的參數 - 尾隨閉包
array.sort { (item1, item2) in return item1 < item2 }
// 作為函數的參數 - 通過數字表示參數
array.sort { return $0 < $1 }
// 作為函數的參數 - 尾隨閉包且隱含返回類型
array.sort { $0 < $1 }
// 作為函數的參數 - 引用已存在的函數
array.sort(<)
References
- Closures
- Closure Expressions in Swift
- Fucking Closure
- Writing completion blocks with closures in Swift
- Enough About Swift Closures to Choke a Horse
- Functions and Closures in Swift
- Swift How-To: Writing Trailing Closures
知識來源:http://lib.csdn.net/article/swift/474
Swift學習筆記之閉包