SWift學習筆記
閉包
閉包表達式
閉包是自包含的函數代碼塊,可以在代碼中被傳遞和使用夺脾。Swift 中的閉包與 C 和 Objective-C 中的代碼塊(b
locks)以及其他一些編程語言中的匿名函數比較相似狸页。
閉包可以捕獲和存儲其所在上下文中任意常量和變量的引用。這就是所謂的閉合并包裹著這些常量和變量,俗稱 閉包绸硕。Swift 會為您管理在捕獲過程中涉及到的所有內存操作钠署。
函數實際上也是一直特殊的閉包,閉包采取以下三種形式:
- 全局函數是一個有名字但不會捕獲任何值的閉包
- 嵌套函數是一個有名字并可以捕獲其封閉函數域內值的閉包
- 閉包表達式是一個利用輕量級語法所寫的可以捕獲其上下文中變量或常量值的匿名閉包
閉包表達式語法有如下形式
{ (parameters) -> returnType in
statements
}
parameters可為常量勾怒,變量婆排,inout,不能提供默認值。也可以在參數列表的最后使用可變參數笔链。
元組也可以作為參數和返回值
exp:
let someClosure2:( String, String)->String = { (var s1:String , var s2:String)->String in
s1 += " "
s2 += "!"
return s1 + s2
}
任何情況下,通過內聯(lián)閉包表達式構造的閉包作為參數傳遞給函數或方法時,都可以推斷出閉包的參數和 返回值類型段只。 這意味著閉包作為函數或者方法的參數時,您幾乎不需要利用完整格式構造內聯(lián)閉包。
exp:
let someColsure3:(String,String)->String = { s1,s2 in
return s1+s2
}
單表達式閉包隱式返回(Implicit Return From Single-Expression Clossures)
單行表達式閉包可以通過省略 return 關鍵字來隱式返回單行表達式的結果.
let someColsure3:(String,String)->String = { s1,s2 in s1+s2}
Swift 自動為內聯(lián)閉包提供了參數名稱縮寫功能,您可以直接通過 $0 , $1 , $2 來順序調用閉包的參數,以此 類推鉴扫。
let someColsure5:(String,String)->String = { $0 + $1}
尾隨閉包
如果您需要將一個很長的閉包表達式作為最后一個參數傳遞給函數,可以使用尾隨閉包來增強函數的可讀性赞枕。尾
隨閉包是一個書寫在函數括號之后的閉包表達式,函數支持將其作為最后一個參數調用:
func someFunctionThatTakesAClosure(closure: () -> Void) { // 函數體部分
}
// 以下是不使用尾隨閉包進行函數調用 someFunctionThatTakesAClosure({
// 閉包主體部分 })
// 以下是使用尾隨閉包進行函數調用 someFunctionThatTakesAClosure() {
// 閉包主體部分 }
exp:
func funTakeClosure(closure:(String,String)->String) -> String {
return closure("some", "closure")
}
let resault_cl = funTakeClosure({$0+$1})
let resault2_cl = funTakeClosure(){
$0 + "++" + $1
}
// 函數只有一個參數時 函數名后面的()括號也可以忽略
let resault3_cl = funTakeClosure{
$0 + "++" + $1
}
捕獲值
閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經不存在,閉包仍然可
以在閉包函數體內引用和修改這些值坪创。
Swift 中,可以捕獲值的閉包的最簡單形式是嵌套函數,也就是定義在其他函數的函數體內的函數炕婶。嵌套函數可 以捕獲其外部函數所有的參數以及定義的常量和變量。
func makeIncrementor(forIcrement amount:Int) -> ()->Int {
var runningTotal = 0;
func Incrementor()->Int{
runningTotal += amount
return runningTotal
}
return Incrementor;
}
var Incrementor = makeIncrementor(forIcrement: 5)
Incrementor()
// 返回結果 5
Incrementor()
// 返回結果 10
Incrementor = makeIncrementor(forIcrement: 10)
Incrementor()
// 返回結果 10
Incrementor()
// 返回結果 20
閉包是引用類型(Closures Are Reference Types)
無論您將函數或閉包賦值給一個常量還是變量,您實際上都是將常量或變量的值設置為對應函數或閉包的引用莱预。
這也意味著如果您將閉包賦值給了兩個不同的常量或變量,兩個值都會指向同一個閉包:
let constIncrementor = Incrementor
Incrementor()
// 結果 30
非逃逸閉包(Nonescaping Closures)
當一個閉包作為參數傳到一個函數中,但是這個閉包在函數返回之后才被執(zhí)行,我們稱該閉包從函數中逃逸柠掂。當 你定義接受閉包作為參數的函數時,你可以在參數名之前標注 @noescape ,用來指明這個閉包是不允許“逃 逸”出這個函數的。將閉包標注 @noescape 能使編譯器知道這個閉包的生命周期(譯者注:閉包只能在函數體中 被執(zhí)行,不能脫離函數體執(zhí)行,所以編譯器明確知道運行時的上下文),從而可以進行一些比較激進的優(yōu)化依沮。
var closures:[() -> Void] = []
func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
closure()
//此處將報錯
closures.append(closure)
}
自動閉包
自動閉包是一種自動創(chuàng)建的閉包,用于包裝傳遞給函數作為參數的表達式涯贞。這種閉包不接受任何參數,當它被調
用的時候,會返回被包裝在其中的表達式的值。這種便利語法讓你能夠用一個普通的表達式來代替顯式的閉
包,從而省略閉包的花括號危喉。
自動閉包讓你能夠延遲求值,因為代碼段不會被執(zhí)行直到你調用這個閉包宋渔。延遲求值對于那些有副作用(Side Ef fect)和代價昂貴的代碼來說是很有益處的,因為你能控制代碼什么時候執(zhí)行。
函數通過將參數標記為@autoclosure 來接收一個自動閉包.
func funAutoclosure(@autoclosure closure:()->String) -> String {
return closure()
}
var autoclosureArry = ["auto", "closure", "string", "func"]
funAutoclosure(autoclosureArry.removeLast())
@autoclosure 特性暗含了 @noescape 特性,這個特性在非逃逸閉包 (頁 0)一節(jié)中有描述姥饰。如果你想讓這個閉包 可以“逃逸”,則應該使用 @autoclosure(escaping) 特性.