swift--閉包7

閉包是自包含的函數(shù)代碼塊,可以在代碼中被傳遞和使用。Swift 中的閉包與 C 和 Objective-C 中的代碼塊(blocks)以及其他一些編程語言中的匿名函數(shù)比較相似。

閉包可以捕獲和存儲其所在上下文中任意常量和變量的引用。被稱為包裹常量和變量。 Swift 會為你管理在捕獲過程中涉及到的所有內(nèi)存操作。

閉包表達(dá)式

sorted 方法

sorted(by:) 方法接受一個閉包,該閉包函數(shù)需要傳入與數(shù)組元素類型相同的兩個值,并返回一個布爾類型值來表明當(dāng)排序結(jié)束后傳入的第一個參數(shù)排在第二個參數(shù)前面還是后面。如果第一個參數(shù)值出現(xiàn)在第二個參數(shù)值前面,排序閉包函數(shù)需要返回true,反之返回false。

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// reversedNames 為 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

閉包表達(dá)式語法

//閉包表達(dá)式語法有如下的一般形式
{ (parameters) -> returnType in
    statements
}

閉包表達(dá)式參數(shù) 可以是 in-out 參數(shù),但不能設(shè)定默認(rèn)值。也可以使用具名的可變參數(shù)

reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

閉包的函數(shù)體部分由關(guān)鍵字in引入。該關(guān)鍵字表示閉包的參數(shù)和返回值類型定義已經(jīng)完成,閉包函數(shù)體即將開始。

根據(jù)上下文推斷類型

因為排序閉包函數(shù)是作為 sorted(by:) 方法的參數(shù)傳入的,Swift 可以推斷其參數(shù)和返回值的類型。sorted(by:) 方法被一個字符串?dāng)?shù)組調(diào)用,因此其參數(shù)必須是 (String, String) -> Bool 類型的函數(shù)。這意味著 (String, String) 和 Bool 類型并不需要作為閉包表達(dá)式定義的一部分。因為所有的類型都可以被正確推斷,返回箭頭(->)和圍繞在參數(shù)周圍的括號也可以被省略:

reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

實際上,通過內(nèi)聯(lián)閉包表達(dá)式構(gòu)造的閉包作為參數(shù)傳遞給函數(shù)或方法時,總是能夠推斷出閉包的參數(shù)和返回值類型。這意味著閉包作為函數(shù)或者方法的參數(shù)時,你幾乎不需要利用完整格式構(gòu)造內(nèi)聯(lián)閉包。

單表達(dá)式閉包隱式返回

單行表達(dá)式閉包可以通過省略 return 關(guān)鍵字來隱式返回單行表達(dá)式的結(jié)果,如上版本的例子可以改寫為:

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

在這個例子中,sorted(by:) 方法的參數(shù)類型明確了閉包必須返回一個 Bool 類型值。因為閉包函數(shù)體只包含了一個單一表達(dá)式(s1 > s2),該表達(dá)式返回 Bool 類型值,因此這里沒有歧義,return 關(guān)鍵字可以省略。

參數(shù)名稱縮寫

Swift 自動為內(nèi)聯(lián)閉包提供了參數(shù)名稱縮寫功能,你可以直接通過 0,1,$2 來順序調(diào)用閉包的參數(shù),以此類推。

如果你在閉包表達(dá)式中使用參數(shù)名稱縮寫,你可以在閉包定義中省略參數(shù)列表,并且對應(yīng)參數(shù)名稱縮寫的類型會通過函數(shù)類型進(jìn)行推斷。in關(guān)鍵字也同樣可以被省略,因為此時閉包表達(dá)式完全由閉包函數(shù)體構(gòu)成:

reversedNames = names.sorted(by: { $0 > $1 } )

運算符方法

實際上還有一種更簡短的方式來編寫上面例子中的閉包表達(dá)式。Swift 的 String 類型定義了關(guān)于大于號(>)的字符串實現(xiàn),其作為一個函數(shù)接受兩個 String 類型的參數(shù)并返回 Bool 類型的值。而這正好與 sorted(by:) 方法的參數(shù)需要的函數(shù)類型相符合。因此,你可以簡單地傳遞一個大于號,Swift 可以自動推斷出你想使用大于號的字符串函數(shù)實現(xiàn):

reversedNames = names.sorted(by: >)

尾隨閉包

如果你需要將一個很長的閉包表達(dá)式作為最后一個參數(shù)傳遞給函數(shù),可以使用尾隨閉包來增強函數(shù)的可讀性。尾隨閉包是一個書寫在函數(shù)括號之后的閉包表達(dá)式,函數(shù)支持將其作為最后一個參數(shù)調(diào)用。在使用尾隨閉包時,你不用寫出它的參數(shù)標(biāo)簽:

值捕獲

閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經(jīng)不存在,閉包仍然可以在閉包函數(shù)體內(nèi)引用和修改這些值。

Swift 中,可以捕獲值的閉包的最簡單形式是嵌套函數(shù),也就是定義在其他函數(shù)的函數(shù)體內(nèi)的函數(shù)。嵌套函數(shù)可以捕獲其外部函數(shù)所有的參數(shù)以及定義的常量和變量。

如果你將閉包賦值給一個類實例的屬性,并且該閉包通過訪問該實例或其成員而捕獲了該實例,你將在閉包和該實例間創(chuàng)建一個循環(huán)強引用。Swift 使用捕獲列表來打破這種循環(huán)強引用

閉包是引用類型

逃逸閉包

當(dāng)一個閉包作為參數(shù)傳到一個函數(shù)中,但是這個閉包在函數(shù)返回之后才被執(zhí)行,我們稱該閉包從函數(shù)中逃逸。當(dāng)你定義接受閉包作為參數(shù)的函數(shù)時,你可以在參數(shù)名之前標(biāo)注 @escaping,用來指明這個閉包是允許“逃逸”出這個函數(shù)的。

一種能使閉包“逃逸”出函數(shù)的方法是,將這個閉包保存在一個函數(shù)外部定義的變量中。舉個例子,很多啟動異步操作的函數(shù)接受一個閉包參數(shù)作為 completion handler。這類函數(shù)會在異步操作開始之后立刻返回,但是閉包直到異步操作結(jié)束后才會被調(diào)用。在這種情況下,閉包需要“逃逸”出函數(shù),因為閉包需要在函數(shù)返回之后被調(diào)用

將一個閉包標(biāo)記為 @escaping 意味著你必須在閉包中顯式地引用 self。比如說,在下面的代碼中,傳遞到 someFunctionWithEscapingClosure(:) 中的閉包是一個逃逸閉包,這意味著它需要顯式地引用 self。相對的,傳遞到 someFunctionWithNonescapingClosure(:) 中的閉包是一個非逃逸閉包,這意味著它可以隱式引用 self。

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}

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

let instance = SomeClass()
instance.doSomething()
print(instance.x)
// 打印出 "200"

completionHandlers.first?()
print(instance.x)
// 打印出 "100"

自動閉包

自動閉包是一種自動創(chuàng)建的閉包,用于包裝傳遞給函數(shù)作為參數(shù)的表達(dá)式。這種閉包不接受任何參數(shù),當(dāng)它被調(diào)用的時候,會返回被包裝在其中的表達(dá)式的值。這種便利語法讓你能夠省略閉包的花括號,用一個普通的表達(dá)式來代替顯式的閉包。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本章將會介紹 閉包表達(dá)式尾隨閉包值捕獲閉包是引用類型逃逸閉包自動閉包枚舉語法使用Switch語句匹配枚舉值關(guān)聯(lián)值原...
    寒橋閱讀 1,629評論 0 3
  • 閉包是自包含的函數(shù)代碼塊,可以在代碼中被傳遞和使用,swift中閉包與c和oc的代碼塊匿名函數(shù)比較相似 閉包可以捕...
    edison0428閱讀 345評論 0 0
  • 86.復(fù)合 Cases 共享相同代碼塊的多個switch 分支 分支可以合并, 寫在分支后用逗號分開。如果任何模式...
    無灃閱讀 1,560評論 1 5
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 3,150評論 2 9
  • 感覺有點難懂,可以參考http://www.itdecent.cn/p/49e7a29a2698 閉包是自包含的...
    CDLOG閱讀 705評論 0 0

友情鏈接更多精彩內(nèi)容