Swift-闭包
//: Playground - noun: a place where people can playimport UIKitvar str = "Hello, playground"
/*在函數 章節中介紹的全局和嵌套函數實際上也是特殊的閉包,閉包采取如下三種形式之一:全局函數是一個有名字但不會捕獲任何值的閉包嵌套函數是一個有名字并可以捕獲其封閉函數域內值的閉包閉包表達式是一個利用輕量級語法所寫的可以捕獲其上下文中變量或常量值的匿名閉包Swift 的閉包表達式擁有簡潔的風格,并鼓勵在常見場景中進行語法優化,主要優化如下:利用上下文推斷參數和返回值類型隱式返回單表達式閉包,即單表達式閉包可以省略return關鍵字參數名稱縮寫尾隨(Trailing)閉包語法*///閉包表達式語法有如下一般形式:
/* { (parameters) -> returnType in
statements
}
*///閉包表達式語法可以使用常量、變量和inout類型作為參數,不提供默認值。 也可以在參數列表的最后使用可變參數。 元組也可以作為參數和返回值。
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]//func backwards(s1: String, s2: String) -> Bool {
// return s1 > s2
//}
//var reversed = names.sort(backwards)var reversed = names.sort({ (s1: String, s2: String) -> Bool inreturn s1 > s2
})//根據上下文推斷類型
/*因為排序閉包函數是作為sort(_:)方法的參數進行傳入的,Swift可以推斷其參數和返回值的類型。 sorted期望第二個參數是類型為(String, String) -> Bool的函數,因此實際上String,String和Bool類型并不需要作為閉包表達式定義中的一部分。 因為所有的類型都可以被正確推斷,返回箭頭 (->) 和圍繞在參數周圍的括號也可以被省略:*///reversed = names.sort( { s1, s2 in return s1 > s2 } )//單表達式閉包隱式返回
//單行表達式閉包可以通過隱藏return關鍵字來隱式返回單行表達式的結果
//reversed = names.sort( { s1, s2 in s1 > s2 } )//參數名稱縮寫
//Swift 自動為內聯函數提供了參數名稱縮寫功能,您可以直接通過$0,$1,$2來順序調用閉包的參數。
/*如果您在閉包表達式中使用參數名稱縮寫,您可以在閉包參數列表中省略對其的定義,并且對應參數名稱縮寫的類型會通過函數類型進行推斷。 in關鍵字也同樣可以被省略,因為此時閉包表達式完全由閉包函數體構成:*/reversed = names.sort( { $0 > $1 } )//運算符函數
/*實際上還有一種更簡短的方式來撰寫上面例子中的閉包表達式。 Swift 的String類型定義了關于大于號 (>) 的字符串實現,其作為一個函數接受兩個String類型的參數并返回Bool類型的值。 而這正好與sort(_:)方法的第二個參數需要的函數類型相符合。 因此,您可以簡單地傳遞一個大于號,Swift可以自動推斷出您想使用大于號的字符串函數實現:*/
reversed = names.sort(>)//尾隨閉包
/*如果您需要將一個很長的閉包表達式作為最后一個參數傳遞給函數,可以使用尾隨閉包來增強函數的可讀性。 尾隨閉包是一個書寫在函數括號之后的閉包表達式,函數支持將其作為最后一個參數調用。*/func someFunctionThatTakesAClosure(closure: () -> Void) {// 函數體部分
}// 以下是不使用尾隨閉包進行函數調用
someFunctionThatTakesAClosure({// 閉包主體部分
})//注意: 如果函數只需要閉包表達式一個參數,當您使用尾隨閉包時,您甚至可以把()省略掉
// 以下是使用尾隨閉包進行函數調用
someFunctionThatTakesAClosure() {// 閉包主體部分
}/*
var digitNames = [0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
var numbers = [16, 58, 510]let strings = numbers.map {(var number) -> String invar output = ""while number > 0 {output = digitNames[number % 10]! + outputnumber /= 10}return output
}
*///捕獲值
/*閉包可以在其定義的上下文中捕獲常量或變量。 即使定義這些常量和變量的原域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值Swift最簡單的閉包形式是嵌套函數,也就是定義在其他函數的函數體內的函數。 嵌套函數可以捕獲其外部函數所有的參數以及定義的常量和變量*/func makeIncrementor(forIncrement amount: Int) -> () -> Int {var runningTotal = 0func incrementor() -> Int {runningTotal += amountreturn runningTotal}return incrementor
}
/*注意: 為了優化,Swift可能會捕捉和保存一份對值的拷貝,如果這個值是不可變或是在閉包外的。 Swift同樣負責被捕捉的所有變量的內存管理,包括釋放不被需要的變量。*/
let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()
incrementByTen()/*如果您創建了另一個incrementor,其會有一個屬于自己的獨立的runningTotal變量的引用。 下面的例子中,incrementBySevne捕獲了一個新的runningTotal變量,該變量和incrementByTen中捕獲的變量沒有任何聯系*/let incremenSecond = makeIncrementor(forIncrement: 7)
incremenSecond()
incremenSecond()incrementByTen()/*注意: 如果您將閉包賦值給一個類實例的屬性,并且該閉包通過指向該實例或其成員來捕獲了該實例,您將創建一個在閉包和實例間的強引用環。 Swift 使用捕獲列表來打破這種強引用環。更多信息,請參考 閉包引起的循環強引用。*///閉包是引用類型
/*無論您將函數/閉包賦值給一個常量還是變量,您實際上都是將常量/變量的值設置為對應函數/閉包的引用。 上面的例子中,incrementByTen指向閉包的引用是一個常量,而并非閉包內容本身。*///如果您將閉包賦值給了兩個不同的常量/變量,兩個值都會指向同一個閉包
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
總結
- 上一篇: vue瀑布流插件vue-waterfal
- 下一篇: 集体唱好混动技术,传统车企最后的倔强?