swift 閉包的學(xué)習(xí)

import UIKit
import os
import Foundation

var 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"]

let funa = backward

var RRName = names.sorted(by: <)

/**
 { (parameters) -> return type in
     statements
 }
 原始結(jié)構(gòu)
 */

let aaa = {(str1 :String,str2:String) -> Bool  in
    return str1 > str2
}
reversedNames = names.sorted(by: {(str1,str2) -> Bool in return str1 > str2})
reversedNames = names.sorted(by: aaa)

/**
根據(jù)上下文推斷類型
因?yàn)榕判蜷]包函數(shù)是作為 sorted(by:) 方法的參數(shù)傳入的违寿,Swift 可以推斷其參數(shù)和返回值的類型欢峰。sorted(by:) 方法被一個(gè)字符串?dāng)?shù)組調(diào)用感挥,因此其參數(shù)必須是 (String, String) -> Bool 類型的函數(shù)。這意味著 (String, String) 和 Bool 類型并不需要作為閉包表達(dá)式定義的一部分。因?yàn)樗械念愋投伎梢员徽_推斷卒落,返回箭頭(->)和圍繞在參數(shù)周圍的括號(hào)也可以被省略:
*/


reversedNames = names.sorted(by: { str1, str2 in return str1 > str2})

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

*/

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

/**
參數(shù)名稱縮寫
Swift 自動(dòng)為內(nèi)聯(lián)閉包提供了參數(shù)名稱縮寫功能嫩与,你可以直接通過(guò) 0,1交排,$2 來(lái)順序調(diào)用閉包的參數(shù)划滋,以此類推。
如果你在閉包表達(dá)式中使用參數(shù)名稱縮寫埃篓,你可以在閉包定義中省略參數(shù)列表处坪,并且對(duì)應(yīng)參數(shù)名稱縮寫的類型會(huì)通過(guò)函數(shù)類型進(jìn)行推斷。閉包接受的參數(shù)的數(shù)量取決于所使用的縮寫參數(shù)的最大編號(hào)架专。in 關(guān)鍵字也同樣可以被省略同窘,因?yàn)榇藭r(shí)閉包表達(dá)式完全由閉包函數(shù)體構(gòu)成:

在這個(gè)例子中,0 和1 表示閉包中第一個(gè)和第二個(gè) String 類型的參數(shù)部脚。因?yàn)?1 是編號(hào)最大的縮寫參數(shù)想邦,所以可以理解為:該閉包需要兩個(gè)參數(shù)。這里的 sorted(by:) 函數(shù)希望得到一個(gè)參數(shù)都是字符串的閉包委刘,因此縮寫參數(shù)0 和 $1 的類型均為 String丧没。
*/


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

print(reversedNames)

/**
在這個(gè)例子中,0 和1 表示閉包中第一個(gè)和第二個(gè) String 類型的參數(shù)锡移。因?yàn)?1 是編號(hào)最大的縮寫參數(shù)呕童,所以可以理解為:該閉包需要兩個(gè)參數(shù)。這里的 sorted(by:) 函數(shù)希望得到一個(gè)參數(shù)都是字符串的閉包淆珊,因此縮寫參數(shù)0 和 $1 的類型均為 String拉庵。
*/


reversedNames = names.sorted(by: >)

extension String{

    func ssss(str:String) -> (Int) {
        return str.count + 5
    }
}

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

/*
下例介紹了如何在 map(_:) 方法中使用尾隨閉包將 Int 類型數(shù)組 [16, 58, 510] 轉(zhuǎn)換為包含對(duì)應(yīng) String 類型的值的數(shù)組 ["OneSix", "FiveEight", "FiveOneZero"]:
**/


let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]


let strings = numbers.map { numberin -> String in
    var number = numberin
    var output = ""
    repeat{
        output = digitNames[number%10]! + output
        number/=10
    }while number > 0
    return output
}
print(strings)


func someFunctionThatTakesAClosure(closure: () -> Void) {
    closure()
    print("someFunctionThatTakesAClosure 被調(diào)用")
    // 函數(shù)體部分
}


var name_val:String = "zs"

func fff() ->Void{
    name_val = "fff"
}
someFunctionThatTakesAClosure(closure: {() -> Void in })
someFunctionThatTakesAClosure(closure: {})
someFunctionThatTakesAClosure {
    name_val = "zlj"
}
print(name_val)
someFunctionThatTakesAClosure(closure: {})
print(name_val)
someFunctionThatTakesAClosure(closure: fff)
print(name_val)

names.sorted(){$1>$0}
names.sorted{$1>$0}

/**
如果一個(gè)函數(shù)接受多個(gè)閉包,您需要省略第一個(gè)尾隨閉包的參數(shù)標(biāo)簽,并為其余尾隨閉包添加標(biāo)簽钞支。例如茫蛹,以下函數(shù)將為圖片庫(kù)加載一張圖片:


 func loadPicture(from server: Server, completion:(Picture) -> Void,
         onFailure: () -> Void) {
     if let picture = download("photo.jpg", from: server){
         completion(picture)
     }else{
         onFailure()
     }
 }

當(dāng)您調(diào)用該函數(shù)以加載圖片時(shí),需要提供兩個(gè)閉包烁挟。第一個(gè)閉包是一個(gè)完成處理程序婴洼,它在成功下載后加載圖片;第二個(gè)閉包是一個(gè)錯(cuò)誤處理程序撼嗓,它向用戶顯示錯(cuò)誤柬采。


 loadPicture(from: someServer){    picture in
     someView.currentPicture = picture
 } onFailure: {
     print("Couldn't download the next picture.")
 }

在本例中,loadPicture(from:completion:onFailure:) 函數(shù)將它的網(wǎng)絡(luò)任務(wù)分配到后臺(tái)且警,并在網(wǎng)絡(luò)任務(wù)完成時(shí)調(diào)用兩個(gè)完成處理程序中的一個(gè)粉捻。通過(guò)這種方法編寫函數(shù),您將能夠把負(fù)責(zé)處理網(wǎng)絡(luò)故障的代碼和成功下載后更新用戶界面的代碼干凈地區(qū)分開斑芜,而不是只使用一個(gè)閉包處理兩種情況肩刃。

注意
完成處理程序可能很難閱讀,特別是您必須嵌套多個(gè)完成處理程序時(shí)杏头。另一種方法是使用異步代碼盈包,如章節(jié)并發(fā) 中所述。

*/

//逃逸閉包

/*
當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中醇王,但是這個(gè)閉包在函數(shù)返回之后才被執(zhí)行呢燥,我們稱該閉包從函數(shù)中逃逸。當(dāng)你定義接受閉包作為參數(shù)的函數(shù)時(shí)寓娩,你可以在參數(shù)名之前標(biāo)注 (‘@escaping’)叛氨,用來(lái)指明這個(gè)閉包是允許“逃逸”出這個(gè)函數(shù)的。
一種能使閉包“逃逸”出函數(shù)的方法是棘伴,將這個(gè)閉包保存在一個(gè)函數(shù)外部定義的變量中力试。舉個(gè)例子,很多啟動(dòng)異步操作的函數(shù)接受一個(gè)閉包參數(shù)作為 completion handler排嫌。這類函數(shù)會(huì)在異步操作開始之后立刻返回畸裳,但是閉包直到異步操作結(jié)束后才會(huì)被調(diào)用。在這種情況下淳地,閉包需要“逃逸”出函數(shù)怖糊,因?yàn)殚]包需要在函數(shù)返回之后被調(diào)用。例如:
*/


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

/**
someFunctionWithEscapingClosure(:) 函數(shù)接受一個(gè)閉包作為參數(shù)颇象,該閉包被添加到一個(gè)函數(shù)外定義的數(shù)組中伍伤。如果你不將這個(gè)參數(shù)標(biāo)記為 @escaping,就會(huì)得到一個(gè)編譯錯(cuò)誤遣钳。
將一個(gè)閉包標(biāo)記為 @escaping 意味著你必須在閉包中顯式地引用 self扰魂。比如說(shuō),在下面的代碼中,傳遞到 someFunctionWithEscapingClosure(
:) 中的閉包是一個(gè)逃逸閉包劝评,這意味著它需要顯式地引用 self姐直。相對(duì)的,傳遞到 someFunctionWithNonescapingClosure(_:) 中的閉包是一個(gè)非逃逸閉包蒋畜,這意味著它可以隱式引用 self声畏。
*/


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

class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 } //逃逸閉包 需要 指定 self
        someFunctionWithNonescapingClosure { x = 200 } // 調(diào)用someFunctionWithNonescapingClosure 會(huì)執(zhí)行closure() 實(shí)際執(zhí)行了 { x = 200 }
    }
}

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

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

/**
自動(dòng)閉包是一種自動(dòng)創(chuàng)建的閉包,用于包裝傳遞給函數(shù)作為參數(shù)的表達(dá)式姻成。這種閉包不接受任何參數(shù)插龄,當(dāng)它被調(diào)用的時(shí)候,會(huì)返回被包裝在其中的表達(dá)式的值科展。這種便利語(yǔ)法讓你能夠省略閉包的花括號(hào)均牢,用一個(gè)普通的表達(dá)式來(lái)代替顯式的閉包。
*/


var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
let customerProvider = {customersInLine.remove(at: 0)} //僅賦值 未執(zhí)行 因?yàn)槭情]包
print(customersInLine.count)

print(customerProvider()) //執(zhí)行后 返回刪除的值 Chris
print("Now serving \(customerProvider())!") //執(zhí)行后返回刪除的 Alex
// 打印出“Now serving Chris!”
print(customersInLine.count)
// 打印出“3”

/**才睹。??
盡管在閉包的代碼中徘跪,customersInLine 的第一個(gè)元素被移除了,不過(guò)在閉包被調(diào)用之前砂竖,這個(gè)元素是不會(huì)被移除的。如果這個(gè)閉包永遠(yuǎn)不被調(diào)用鹃答,那么在閉包里面的表達(dá)式將永遠(yuǎn)不會(huì)執(zhí)行乎澄,那意味著列表中的元素永遠(yuǎn)不會(huì)被移除。請(qǐng)注意测摔,customerProvider 的類型不是 String置济,而是 () -> String,一個(gè)沒有參數(shù)且返回值為 String 的函數(shù)锋八。
將閉包作為參數(shù)傳遞給函數(shù)時(shí)浙于,你能獲得同樣的延時(shí)求值行為。
*/


customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
    print("Now -  serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// 打印出“Now serving Alex!”

/**
上面的 serve(customer:) 函數(shù)接受一個(gè)返回顧客名字的顯式的閉包挟纱。下面這個(gè)版本的 serve(customer:) 完成了相同的操作羞酗,不過(guò)它并沒有接受一個(gè)顯式的閉包,而是通過(guò)將參數(shù)標(biāo)記為 @autoclosure 來(lái)接收一個(gè)自動(dòng)閉包∥煞現(xiàn)在你可以將該函數(shù)當(dāng)作接受 String 類型參數(shù)(而非閉包)的函數(shù)來(lái)調(diào)用檀轨。customerProvider 參數(shù)將自動(dòng)轉(zhuǎn)化為一個(gè)閉包,因?yàn)樵搮?shù)被標(biāo)記了 @autoclosure 特性欺嗤。
*/


// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
    print("Now serving \(customerProvider())!")
}
//serve(customer:{ customersInLine.remove(at: 0)})
serve(customer: customersInLine.remove(at: 0)) //自動(dòng)閉包可以省略括號(hào) '{}'
// 打印“Now serving Ewa!”

/**
注意 ??
過(guò)度使用 autoclosures 會(huì)讓你的代碼變得難以理解参萄。上下文和函數(shù)名應(yīng)該能夠清晰地表明求值是被延遲執(zhí)行的。
/
/
*
如果你想讓一個(gè)自動(dòng)閉包可以“逃逸”煎饼,則應(yīng)該同時(shí)使用 @autoclosure 和 @escaping 屬性讹挎。@escaping 屬性的講解見上面的 逃逸閉包。
*/


// customersInLine i= ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
    customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))

print("Collected \(customerProviders.count) closures.")
// 打印“Collected 2 closures.”
for customerProvider in customerProviders {
    print("Now serving \(customerProvider())!")
}
// 打印“Now serving Barry!”
// 打印“Now serving Daniella!”

/**
總結(jié)

在 函數(shù) 章節(jié)中介紹的全局和嵌套函數(shù)實(shí)際上也是特殊的閉包,閉包采用如下三種形式之一:
1全局函數(shù)是一個(gè)有名字但不會(huì)捕獲任何值的閉包
2嵌套函數(shù)是一個(gè)有名字并可以捕獲其封閉函數(shù)域內(nèi)值的閉包
3閉包表達(dá)式是一個(gè)利用輕量級(jí)語(yǔ)法所寫的可以捕獲其上下文中變量或常量值的匿名閉包

Swift 的閉包表達(dá)式擁有簡(jiǎn)潔的風(fēng)格筒溃,并鼓勵(lì)在常見場(chǎng)景中進(jìn)行語(yǔ)法優(yōu)化马篮,主要優(yōu)化如下:
1利用上下文推斷參數(shù)和返回值類型
2隱式返回單表達(dá)式閉包,即單表達(dá)式閉包可以省略 return 關(guān)鍵字
3參數(shù)名稱縮寫
4尾隨閉包語(yǔ)法

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

對(duì)照:
{ (s1: String, s2: String) -> Bool in
return s1 > s2
}

簡(jiǎn)寫1:{ (s1: String, s2: String) -> Bool in return s1 > s2 }
簡(jiǎn)寫2:{ (s1, s2) in return s1 > s2 } 根據(jù)上下文推斷其參數(shù) 類型以及返回值類型
簡(jiǎn)寫3:{ s1, s2 in return s1 > s2 } 省略括號(hào)
簡(jiǎn)寫4:{ s1, s2 in s1 > s2 }省略 return
簡(jiǎn)寫5: { 0 >1 } 參數(shù)名稱縮寫 你可以直接通過(guò) 0铡羡,1积蔚,2 來(lái)順序調(diào)用閉包的參數(shù),以此類推1代表有兩個(gè)參數(shù),需要按順序?qū)懛駝t報(bào)錯(cuò)
簡(jiǎn)寫6: { >} 或者 > 運(yùn)算符方法
其實(shí)閉包的終結(jié)就是 --->{} 個(gè)人理解.

其他理解:

閉包是引用類型,閉包被賦值給多個(gè)變量他們都執(zhí)行的是同一個(gè)閉包,閉包內(nèi)的捕獲的“值”也是“共用”的.

*/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末烦周,一起剝皮案震驚了整個(gè)濱河市尽爆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌读慎,老刑警劉巖漱贱,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異夭委,居然都是意外死亡幅狮,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門株灸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)崇摄,“玉大人,你說(shuō)我怎么就攤上這事慌烧≈鹨郑” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵屹蚊,是天一觀的道長(zhǎng)厕氨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)汹粤,這世上最難降的妖魔是什么命斧? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮嘱兼,結(jié)果婚禮上国葬,老公的妹妹穿的比我還像新娘。我一直安慰自己芹壕,他們只是感情好胃惜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著哪雕,像睡著了一般船殉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斯嚎,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天利虫,我揣著相機(jī)與錄音挨厚,去河邊找鬼。 笑死糠惫,一個(gè)胖子當(dāng)著我的面吹牛疫剃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播硼讽,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼巢价,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了固阁?” 一聲冷哼從身側(cè)響起壤躲,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎备燃,沒想到半個(gè)月后碉克,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡并齐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年漏麦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片况褪。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撕贞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出测垛,到底是詐尸還是另有隱情捏膨,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布赐纱,位于F島的核電站脊奋,受9級(jí)特大地震影響熬北,放射性物質(zhì)發(fā)生泄漏疙描。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一讶隐、第九天 我趴在偏房一處隱蔽的房頂上張望起胰。 院中可真熱鬧,春花似錦巫延、人聲如沸效五。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)畏妖。三九已至,卻和暖如春疼阔,著一層夾襖步出監(jiān)牢的瞬間戒劫,已是汗流浹背半夷。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留迅细,地道東北人巫橄。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像茵典,于是被迫代替她去往敵國(guó)和親湘换。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容