標籤:func 大致 rar 總結 記憶體管理 ber www pre alias
簡介 (真的很簡)
閉包的完整形態是這個樣子的:
{ (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學習筆記之閉包