swift3.1 函數(shù)和閉包

函數(shù)

func greet(person: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
        return greet(person: person)
    }
}
print(greet(person: "Tim", alreadyGreeted: true))
// Prints "Hello again, Tim!"

//沒有返回值的函數(shù),實(shí)際上返回了Void, 一個(gè)空的元組()。

//返回多個(gè)值
func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

//返回可選型的元組 (Int, Int)? is different from a tuple that contains optional types such as (Int?, Int?). 

摘錄來自: Apple Inc. “The Swift Programming Language (Swift 3.1)”。 iBooks. 
func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

//函數(shù)辨識(shí)標(biāo)簽和參數(shù)名

閉包

//一般形式
let calAdd:(Int,Int)->(Int) = {
    (a:Int,b:Int) -> Int in
    return a + b
}
print(calAdd(100,150))
 
//Swift可以根據(jù)閉包上下文推斷參數(shù)和返回值的類型,所以上面的例子可以簡(jiǎn)化如下
let calAdd2:(Int,Int)->(Int) = {
    a,b in  //也可以寫成(a,b) in
    return a + b
}
print(calAdd2(150,100))
//上面省略了返回箭頭和參數(shù)及返回值類型,以及參數(shù)周圍的括號(hào)。當(dāng)然你也可以加括號(hào),為了好看點(diǎn),看的清楚點(diǎn)。(a,b)
 
//單行表達(dá)式閉包可以隱式返回,如下,省略return
let calAdd3:(Int,Int)->(Int) = {(a,b) in a + b}
print(calAdd3(50,200))
 
//如果閉包沒有參數(shù),可以直接省略“in”
let calAdd4:()->Int = {return 100 + 150}
print("....\(calAdd4())")
 
//這個(gè)寫法,我隨便寫的。打印出“我是250”
//這個(gè)是既沒有參數(shù)也沒返回值,所以把return和in都省略了
let calAdd5:()->Void = {print("我是250")}
calAdd5()

//也可以關(guān)鍵字“typealias”先聲明一個(gè)閉包數(shù)據(jù)類型。類似于OC中的typedef起別名
typealias AddBlock = (Int, Int) -> (Int)
 
let Add:AddBlock = {
    (c,d) in
    return c + d
}
 
let Result = Add(100,150)
print("Result = \(Result)")

尾隨閉包
//若將閉包作為函數(shù)最后一個(gè)參數(shù),可以省略參數(shù)標(biāo)簽,然后將閉包表達(dá)式寫在函數(shù)調(diào)用括號(hào)后面
func testFunction(testBlock: ()->Void){
    //這里需要傳進(jìn)來的閉包類型是無參數(shù)和無返回值的
    testBlock()
}
//正常寫法
testFunction(testBlock: {
    print("正常寫法")
})
//尾隨閉包寫法
testFunction(){
    print("尾隨閉包寫法")
}
//也可以把括號(hào)去掉,也是尾隨閉包寫法。推薦寫法
testFunction { 
    print("去掉括號(hào)的尾隨閉包寫法")
}

//值捕獲
func captureValue(sums amount:Int) -> ()->Int{
    var total = 0
    func incrementer()->Int{
        total += amount
        return total
    }
    return incrementer
}
 
print(captureValue(sums: 10)())
print(captureValue(sums: 10)())
print(captureValue(sums: 10)())
//打印"10 10 10"

let referenceFunc = captureValue(sums: 10)
print(referenceFunc())
print(referenceFunc())
print(referenceFunc())
//打印"10 20 30"

func captureValue2(sums amount:Int) -> ()->Int{
    var total = 0
    let AddBlock:()->Int = {
        total += amount
        return total
    }
    return AddBlock
}
 
let testBlock = captureValue2(sums: 100)
print(testBlock())
print(testBlock())
print(testBlock())

//由上面的例子都可以證得,函數(shù)和閉包都是引用類型

逃逸閉包
當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中,需要這個(gè)閉包在函數(shù)返回之后才被執(zhí)行,我們就稱該閉包從函數(shù)種逃逸。一般如果閉包在函數(shù)體內(nèi)涉及到異步操作,但函數(shù)卻是很快就會(huì)執(zhí)行完畢并返回的,閉包必須要逃逸掉,以便異步操作的回調(diào)。

//例1
func doSomething(some: @escaping () -> Void){
    //延時(shí)操作,注意這里的單位是秒
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
        //1秒后操作
        some()
    }
    print("函數(shù)體")
}
doSomething {
    print("逃逸閉包")
}
 
//例2
var comletionHandle: ()->String = {"約嗎?"}
 
func doSomething2(some: @escaping ()->String){
    comletionHandle = some
}
doSomething2 {
    return "叔叔,我們不約"
}
print(comletionHandle())
 
//將一個(gè)閉包標(biāo)記為@escaping意味著你必須在閉包中顯式的引用self。
//其實(shí)@escaping和self都是在提醒你,這是一個(gè)逃逸閉包,
//別誤操作導(dǎo)致了循環(huán)引用!而非逃逸包可以隱式引用self。
 
//例子如下
var completionHandlers: [() -> Void] = []
//逃逸
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
//非逃逸
func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}
 
class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
}

自動(dòng)閉包
顧名思義,自動(dòng)閉包是一種自動(dòng)創(chuàng)建的閉包,封裝一堆表達(dá)式在自動(dòng)閉包中,然后將自動(dòng)閉包作為參數(shù)傳給函數(shù)。而自動(dòng)閉包是不接受任何參數(shù)的,但可以返回自動(dòng)閉包中表達(dá)式產(chǎn)生的值。
自動(dòng)閉包讓你能夠延遲求值,直到調(diào)用這個(gè)閉包,閉包代碼塊才會(huì)被執(zhí)行。說白了,就是語法簡(jiǎn)潔了,有點(diǎn)懶加載的意思。

var array = ["I","have","a","apple"]
print(array.count)
//打印出"4"
 
let removeBlock = {array.remove(at: 3)}//測(cè)試了下,這里代碼超過一行,返回值失效。
print(array.count)
//打印出"4"
 
print("執(zhí)行代碼塊移除\(removeBlock())")
//打印出"執(zhí)行代碼塊移除apple" 這里自動(dòng)閉包返回了apple值
 
print(array.count)
//打印出"3"
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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