之前學(xué)習(xí)swift時(shí)的個(gè)人筆記言秸,根據(jù)github:the-swift-programming-language-in-chinese學(xué)習(xí)、總結(jié)迎捺,將重要的內(nèi)容提取举畸,加以理解后整理為學(xué)習(xí)筆記,方便以后查詢用凳枝。詳細(xì)可以參考the-swift-programming-language-in-chinese抄沮,或者蘋果官方英文版文檔
當(dāng)前版本是swift2.2
函數(shù)
func sayHello(personName: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return sayHelloAgain(personName)
} else {
return sayHello(personName)
}
}
函數(shù)參數(shù)名稱(Function Parameter Names)
函數(shù)參數(shù)都有一個(gè)外部參數(shù)名(external parameter name)和一個(gè)局部參數(shù)名(local parameter name)跋核。外部參數(shù)名用于在函數(shù)調(diào)用時(shí)標(biāo)注傳遞給函數(shù)的參數(shù),局部參數(shù)名在函數(shù)的實(shí)現(xiàn)內(nèi)部使用叛买。
func someFunction(firstParameterName: Int, secondParameterName: Int) {
// function body goes here
// firstParameterName and secondParameterName refer to
// the argument values for the first and second parameters
}
someFunction(1, secondParameterName: 2)
一般情況下砂代,第一個(gè)參數(shù)省略其外部參數(shù)名,第二個(gè)以及隨后的參數(shù)使用其局部參數(shù)名作為外部參數(shù)名率挣。所有參數(shù)必須有獨(dú)一無二的局部參數(shù)名刻伊。盡管多個(gè)參數(shù)可以有相同的外部參數(shù)名,但不同的外部參數(shù)名能讓你的代碼更有可讀性椒功。
你可以在局部參數(shù)名前指定外部參數(shù)名捶箱,中間以空格分隔:
func someFunction(externalParameterName localParameterName: Int) {
// function body goes here, and can use localParameterName
// to refer to the argument value for that parameter
}
如果你提供了外部參數(shù)名(包括局部參數(shù)名作為外部參數(shù)名的情況),那么函數(shù)在被調(diào)用時(shí)动漾,必須使用外部參數(shù)名丁屎。如果想忽略外部參數(shù)名,使用_替代即可
默認(rèn)參數(shù)值(Default Parameter Values)
你可以在函數(shù)體中為每個(gè)參數(shù)定義默認(rèn)值(Deafult Values)旱眯。當(dāng)默認(rèn)值被定義后晨川,調(diào)用這個(gè)函數(shù)時(shí)可以忽略這個(gè)參數(shù)。
func someFunction(parameterWithDefault: Int = 12) {
}
someFunction(6) // parameterWithDefault is 6
someFunction() // parameterWithDefault is 12
將帶有默認(rèn)值的參數(shù)放在函數(shù)參數(shù)列表的最后键思。這樣可以保證在函數(shù)調(diào)用時(shí)础爬,非默認(rèn)參數(shù)的順序是一致的,同時(shí)使得相同的函數(shù)在不同情況下調(diào)用時(shí)顯得更為清晰吼鳞。不過不放在最后也是可以的
可變參數(shù)(Variadic Parameters)
一個(gè)可變參數(shù)(variadic parameter)可以接受零個(gè)或多個(gè)值看蚜。函數(shù)調(diào)用時(shí),你可以用可變參數(shù)來指定函數(shù)參數(shù)可以被傳入不確定數(shù)量的輸入值赔桌。通過在變量類型名后面加入(...)的方式來定義可變參數(shù)供炎。
可變參數(shù)的傳入值在函數(shù)體中變?yōu)榇祟愋偷囊粋€(gè)數(shù)組。例如疾党,一個(gè)叫做 numbers 的 Double... 型可變參數(shù)音诫,在函數(shù)體內(nèi)可以當(dāng)做一個(gè)叫 numbers 的 [Double] 型的數(shù)組常量。
// 求算數(shù)平均數(shù)
func arithmeticMean(numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// 使用AnyObject就類似print函數(shù)了
func alvalible(num:AnyObject...) {
print(num[0],num[1])
}
常量參數(shù)和變量參數(shù)
函數(shù)參數(shù)默認(rèn)是常量雪位。試圖在函數(shù)體中更改參數(shù)值將會(huì)導(dǎo)致編譯錯(cuò)誤竭钝。
通過在參數(shù)名前加關(guān)鍵字 var 來定義變量參數(shù):
func alignRight(var astring: String) -> String {
astring += "123"
return astring
}
swift是值傳遞的,可變參數(shù)作用域只在函數(shù)內(nèi)部雹洗,對(duì)調(diào)用者不產(chǎn)生影響香罐,和C中的指針傳遞不一樣,如果想達(dá)到C指針的效果时肿,可以使用輸入輸出參數(shù)
輸入輸出參數(shù)
變量參數(shù)庇茫,正如上面所述,僅僅能在函數(shù)體內(nèi)被更改螃成。如果你想要一個(gè)函數(shù)可以修改參數(shù)的值旦签,并且想要在這些修改在函數(shù)調(diào)用結(jié)束后仍然存在查坪,那么就應(yīng)該把這個(gè)參數(shù)定義為輸入輸出參數(shù)(In-Out Parameters)。調(diào)用的時(shí)候?qū)崊⒈仨毧勺兡牛壹由?amp;
func swapTwoInts(inout a: Int, inout _ b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
輸入輸出參數(shù)不能有默認(rèn)值偿曙,而且可變參數(shù)不能用 inout 標(biāo)記。如果你用 inout 標(biāo)記一個(gè)參數(shù)淋淀,這個(gè)參數(shù)不能被 var 或者 let 標(biāo)記遥昧。
函數(shù)參數(shù)
func addTwoInts(a: Int, _ b: Int) -> Int {
return a + b
}
func printHelloWorld() {
print("hello, world")
}
第一個(gè)函數(shù)的類型是(Int, Int) -> Int
,可以解讀為“這個(gè)函數(shù)類型有兩個(gè) Int 型的參數(shù)并返回一個(gè) Int 型的值朵纷√砍簦”。第二個(gè)() -> Void
在 Swift 中袍辞,使用函數(shù)類型就像使用其他類型一樣鞋仍。例如,你可以定義一個(gè)類型為函數(shù)的常量或變量搅吁,并將適當(dāng)?shù)暮瘮?shù)賦值給它:
var mathFunction: (Int, Int) -> Int = addTwoInts
mathFunction(2, 3) // 直接使用
這個(gè)可以解讀為:
“定義一個(gè)叫做 mathFunction 的變量威创,類型是‘一個(gè)有兩個(gè) Int 型的參數(shù)并返回一個(gè) Int 型的值的函數(shù)’,并讓這個(gè)新變量指向 addTwoInts 函數(shù)”谎懦。
就像其他類型一樣肚豺,當(dāng)賦值一個(gè)函數(shù)給常量或變量時(shí),你可以讓 Swift 來推斷其函數(shù)類型:
let anotherMathFunction = addTwoInts
參數(shù)為函數(shù)類型
func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \\(mathFunction(a, b))")
}
函數(shù)類型作為返回類型
func stepForward(input: Int) -> Int {
return input + 1
}
func stepBackward(input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
return backwards ? stepBackward : stepForward
}
嵌套函數(shù)
嵌套函數(shù)(Nested Functions)
這章中你所見到的所有函數(shù)都叫全局函數(shù)(global functions)界拦,它們定義在全局域中吸申。你也可以把函數(shù)定義在別的函數(shù)體中,稱作嵌套函數(shù)(nested functions)享甸。
默認(rèn)情況下截碴,嵌套函數(shù)是對(duì)外界不可見的,但是可以被它們的外圍函數(shù)(被嵌套的函數(shù)即例中的chooseStepFunction
)調(diào)用蛉威。一個(gè)外圍函數(shù)也可以返回它的某一個(gè)嵌套函數(shù)日丹,使得這個(gè)函數(shù)可以在其他域中被使用。
你可以用返回嵌套函數(shù)的方式重寫 chooseStepFunction(_:) 函數(shù):
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backwards ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
print("\\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!
閉包
閉包表達(dá)式語法有如下一般形式:
{ (parameters) -> returnType in
statements
}
閉包表達(dá)式語法可以使用常量蚯嫌、變量和inout類型作為參數(shù)哲虾,不能提供默認(rèn)值。也可以在參數(shù)列表的最后使用可變參數(shù)择示。元組也可以作為參數(shù)和返回值束凑。
sort(_:)
方法接受一個(gè)閉包,該閉包函數(shù)需要傳入與數(shù)組元素類型相同的兩個(gè)值对妄,并返回一個(gè)布爾類型值來表明當(dāng)排序結(jié)束后傳入的第一個(gè)參數(shù)排在第二個(gè)參數(shù)前面還是后面。如果第一個(gè)參數(shù)值出現(xiàn)在第二個(gè)參數(shù)值前面敢朱,排序閉包函數(shù)需要返回true剪菱,反之返回false摩瞎。sort函數(shù)會(huì)將數(shù)組里面的元素按照冒泡排序一樣的返回給s1,s2兩個(gè)參數(shù)孝常,然后進(jìn)行比較排序旗们。
函數(shù)對(duì)應(yīng)的閉包表達(dá)式版本的代碼:
reversed = names.sort({ (s1: String, s2: String) -> Bool in
return s1 > s2
})
然而在內(nèi)聯(lián)閉包表達(dá)式中,函數(shù)和返回值類型都寫在大括號(hào)內(nèi)构灸,而不是大括號(hào)外上渴。
閉包的函數(shù)體部分由關(guān)鍵字in引入。該關(guān)鍵字表示閉包的參數(shù)和返回值類型定義已經(jīng)完成喜颁,閉包函數(shù)體即將開始稠氮。
因?yàn)榕判蜷]包函數(shù)是作為sort(_:)
方法的參數(shù)傳入的,Swift 可以推斷其參數(shù)和返回值的類型半开。sort(_:)
方法被一個(gè)字符串?dāng)?shù)組調(diào)用隔披,因此其參數(shù)必須是(String, String) -> Bool
類型的函數(shù)。這意味著(String, String)
和Bool類型并不需要作為閉包表達(dá)式定義的一部分删掀。因?yàn)樗械念愋投伎梢员徽_推斷噪珊,返回箭頭(->)和圍繞在參數(shù)周圍的括號(hào)也可以被省略:
reversed = names.sort( { s1, s2 in return s1 > s2 } )
實(shí)際上任何情況下检激,通過內(nèi)聯(lián)閉包表達(dá)式構(gòu)造的閉包作為參數(shù)傳遞給函數(shù)或方法時(shí),都可以推斷出閉包的參數(shù)和返回值類型鬓长。 這意味著閉包作為函數(shù)或者方法的參數(shù)時(shí),您幾乎不需要利用完整格式構(gòu)造內(nèi)聯(lián)閉包尝江。
單行表達(dá)式閉包可以通過省略return關(guān)鍵字來隱式返回單行表達(dá)式的結(jié)果涉波,如上版本的例子可以改寫為:
reversed = names.sort( { s1, s2 in s1 > s2 } )
在這個(gè)例子中,sort(_:)方法的第二個(gè)參數(shù)函數(shù)類型明確了閉包必須返回一個(gè)Bool類型值茂装。因?yàn)殚]包函數(shù)體只包含了一個(gè)單一表達(dá)式(s1 > s2)怠蹂,該表達(dá)式返回Bool類型值,因此這里沒有歧義少态,return關(guān)鍵字可以省略城侧。
參數(shù)名稱縮寫
Swift 自動(dòng)為內(nèi)聯(lián)閉包提供了參數(shù)名稱縮寫功能,您可以直接通過$0彼妻,$1嫌佑,$2來順序調(diào)用閉包的參數(shù),以此類推侨歉。
尾隨閉包(Trailing Closures)
如果您需要將一個(gè)很長(zhǎng)的閉包表達(dá)式作為最后一個(gè)參數(shù)傳遞給函數(shù)屋摇,可以使用尾隨閉包來增強(qiáng)函數(shù)的可讀性。尾隨閉包是一個(gè)書寫在函數(shù)括號(hào)之后的閉包表達(dá)式幽邓,函數(shù)支持將其作為最后一個(gè)參數(shù)調(diào)用:
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函數(shù)體部分
}
// 以下是不使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure({
// 閉包主體部分
})
// 以下是使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure() {
// 閉包主體部分
}
在閉包表達(dá)式語法一節(jié)中作為sort(_:)方法參數(shù)的字符串排序閉包可以改寫為:
reversed = names.sort() { $0 > $1 }
如果函數(shù)只需要閉包表達(dá)式一個(gè)參數(shù)炮温,當(dāng)您使用尾隨閉包時(shí),您甚至可以把()省略掉:
reversed = names.sort { $0 > $1 }
map(_:)
函數(shù)牵舵,它接受一個(gè)具有一個(gè)參數(shù)和一個(gè)返回值的閉包柒啤,它會(huì)遍歷sortArr數(shù)組的每一個(gè)元素并將其賦給閉包參數(shù)倦挂,閉包的返回值將組成一個(gè)新的數(shù)組作為map函數(shù)的最終返回。新生產(chǎn)的數(shù)組元素與之前的數(shù)組一一對(duì)應(yīng)
let sortArr = [1,2,3,4]
let strArr = sortArr.map{ (temp) -> String in // 結(jié)果 strArr = ["4", "5", "6", "7"]
return "\(temp + 3)"
}
捕獲值(Capturing Values)
閉包可以在其被定義的上下文中捕獲常量或變量担巩。即使定義這些常量和變量的原作用域已經(jīng)不存在方援,閉包仍然可以在閉包函數(shù)體內(nèi)引用和修改這些值。
逃逸閉包
當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中涛癌,但是這個(gè)閉包在函數(shù)返回之后才被執(zhí)行犯戏,我們稱該閉包從函數(shù)中逃逸∪埃可以在參數(shù)名之前標(biāo)注@noescape先匪,用來指明這個(gè)閉包是不允許“逃逸”出這個(gè)函數(shù)的,即這個(gè)函數(shù)執(zhí)行完成之后閉包就被釋放了假颇。如果強(qiáng)制給一個(gè)不允許“逃逸”的閉包賦值給全局變量則會(huì)編譯錯(cuò)誤
將閉包作為參數(shù)傳遞給函數(shù)時(shí)胚鸯,你能獲得同樣的延時(shí)求值行為。
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serveCustomer(customerProvider: () -> String) {
print("Now serving \\(customerProvider())!")
}
serveCustomer( { customersInLine.removeAtIndex(0) } )
// prints "Now serving Alex!"
serveCustomer(_:)
接受一個(gè)返回顧客名字的顯式的閉包笨鸡。下面這個(gè)版本的serveCustomer(_:)
完成了相同的操作姜钳,不過它并沒有接受一個(gè)顯式的閉包,而是通過將參數(shù)標(biāo)記為@autoclosure來接收一個(gè)自動(dòng)閉包⌒魏模現(xiàn)在你可以將該函數(shù)當(dāng)做接受String類型參數(shù)的函數(shù)來調(diào)用哥桥。customerProvider參數(shù)將自動(dòng)轉(zhuǎn)化為一個(gè)閉包,因?yàn)樵搮?shù)被標(biāo)記了@autoclosure特性激涤。
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serveCustomer(@autoclosure customerProvider: () -> String) {
print("Now serving \\(customerProvider())!")
}
serveCustomer(customersInLine.removeAtIndex(0))
// prints "Now serving Ewa!"
@autoclosure特性暗含了@noescape特性,如果你想讓這個(gè)閉包可以“逃逸”拟糕,則應(yīng)該使用@autoclosure(escaping)特性.