Swift講解專題八——閉包

Swift講解專題八——閉包

1、引言

        Swift中的閉包是有必定功能的代碼塊,這十分相似於Objective-C中的block語法。Swift中的閉包語法風格十分簡潔,其做用和函數的做用類似。算法

2、從一個系統函數看閉包

        Swift標準函數庫中提供了一個sort排序函數,對於已經元素類型的數組,調用sort函數會進行從新排序並返回新的排序後的數組。這個sort函數能夠接收一個返回值爲Bool類型的閉包,來肯定第一個元素是否排在第二個元素前面。代碼示例以下:api

var array = [3,21,5,2,64]
func func1(param1:Int,param2:Int) -> Bool {
    return param1>param2
}
//經過傳入函數的方式
//array = [64,21,5,3,2]
array = array.sort(func1)
//經過閉包的方式
//array = [2,3,5,21,64]
array = array.sort({(param:Int,param2:Int)->Bool in
                        return param<param2
                    })

Swift語言有一個很顯著的特色就是簡潔,能夠經過上下文推斷出類型的狀況通常開發均可以將類型的書寫省略,這也是Swift語言設計的一個思路,因爲閉包是做爲函數的參數傳入函數中的,由於函數參數的類型是肯定,所以閉包的類型是能夠被編譯器推斷出來的,開發者也能夠將閉包的參數類型和返回值省略,上面的代碼能夠簡寫以下:數組

//將閉包的參數類型和返回值都省略
array = array.sort({(p1,p2) in return p1>p2})

實際上,若是閉包中的函數體只有一行代碼,能夠將return關鍵字也省略,這時會隱式的返回此行代碼的值,以下:網絡

array = array.sort({(p1,p2) in   p1>p2})

看到上面的表達式,是否是有點小震驚,閉包表達式居然能夠簡寫成這樣!然而,你仍是小看的Swift開發團隊,後面的語法規則會讓你明白什麼是簡潔的極致。能夠看到上面的代碼實現仍是有3部分:參數和返回值,閉包關鍵字,函數體。參數和返回值便是參數列表,p1,p2,雖然省略了參數類型和返回值類型,但這部分的模塊還在,閉包關鍵字便是in,它用來表示下面將是閉包的函數體,p1>p2便是函數體,只是這裏省略了return關鍵字。閉包中既然參數類型和返回值類型編譯器均可以本身推斷出來,那麼參數的數量編輯器也是能夠自行推斷的,所以,參數列表實際上也是多餘的,閉包中會自動生成一些參數名稱,和實際的參數數量向對應,例如上面sort函數中的閉包有兩個參數,系統會自動生成$0和$1這兩個參數名,開發者能夠直接使用,由於參數列表都會省略了,那麼也再也不須要閉包關鍵字in來分隔參數列表與函數體,這時,閉包的寫法實際上變成了以下的模樣:閉包

array = array.sort({$0<$1})

你沒有看錯,加上左右的大括號,一共7個字符,完成了一個排序算法。除了Swift,我不知道是否還有第二種語言能夠作到。拋開閉包不說,Swift中還有一種語法,其能夠定義類型的運算符方法,例如String類型能夠經過=,<,>來進行比較,其實是String類中實現了這些運算符方法,在某種意義上說,一個運算符即相似與一個函數,那麼好了,sort函數中須要傳入的方法對於某些類型來講實際上只是須要一個運算符,示例以下:app

array = array.sort(>)

此次你能夠真的震驚了,完成排序新算法只須要一個字符,徹徹底底的一個字符。異步

3、Swift中閉包的更多特色

        Swift中的閉包還有一個有趣的特色,首先閉包是做爲參數傳入另外一個函數中的,所以常規的寫法是將閉包的大括號寫在函數的參數列表小括號中,若是閉包中的代碼不少,這時在代碼結構上來看會變得並不太清晰,爲了解決這個問題,Swift中這樣規定:若是這個閉包參數是函數的最後一個參數,開發者能夠將其拉出小括號,在函數尾部實現閉包代碼,示例以下:編輯器

//閉包結尾
func func2(param1:Int,param2:()->Void)->Void{
    param2()
    print("調用了func2函數")
}
func2(0){
        print("閉包中的內容")
}

若是一個函數中只有一個參數,且這個參數是一個閉包,那麼開發者使用閉包結尾這種寫法,徹底能夠將函數的參數列表小括號也省略掉,示例以下:函數

func func3(param:()->Void)->Void{
    param()
    print("調用了func3函數")
}
func3{
    print("閉包中的內容")
}

Swift中還有一個閉包逃逸的概念,這個很好理解,當閉包做爲參數傳遞進函數時,若是這個閉包只在函數中被使用,則開發者能夠將這個閉包聲明成非逃逸的,即告訴系統當此函數結束後,這個閉包的聲明週期也將結束,這樣作的好處是能夠提升代碼性能,將閉包聲明稱非逃逸的類型使用@noescape關鍵字,示例以下:性能

func func3(@noescape param:()->Void)->Void{
    param()
    print("調用了func3函數")
}
func3{
    print("閉包中的內容")
}

逃逸的閉包經常使用於異步的操做,例如這個閉包是異步處理一個網絡請求,只有當請求結束後,閉包的聲明週期才結束。非逃逸的閉包還有一個有趣的特色,在其內部若是須要使用self這個關鍵字,self能夠被省略。

        閉包也能夠被自動的生成,這種閉包被稱爲自動閉包,自動閉包能夠自動將表達式封裝成閉包,開發者不須要再寫閉包的大括號格式,自動閉包不接收參數,返回值爲其中表達式的值。示例以下:

//自動閉包演示
var list = [1,2,3,4,5,6]
//建立一個顯式閉包
let closures = {
    list.removeFirst()
    list.append(7)
}
//將打印[1,2,3,4,5,6]
print(list)
//執行閉包
closures()
//將打印[2,3,4,5,6,7]
print(list)
func func4(closure:()->Void) -> Void {
    //執行顯式的閉包
    closures()
}
func func5(@autoclosure auto:()->Void) -> Void {
    //執行自動閉包
    auto()
}
//顯式閉包 須要大括號
func4(closures)
//將打印[3,4,5,6,7,7]
print(list)
//將表達式自動生成閉包
func5(list.append(8))
//將打印[3,4,5,6,7,7,8]
print(list)

自動閉包默認是非逃逸的,若是要使用逃逸的閉包,須要手動聲明,以下:

func func5(@autoclosure(escaping) auto:()->Void) -> Void {
    //執行自動閉包
    auto()
}

專一技術,熱愛生活,交流技術,也作朋友。

——琿少 QQ羣:203317592

相關文章
相關標籤/搜索