Swift-閉包

weixin_33670713發表於2016-11-21

Swift中的閉包和OC中的Block類似,語法格式不一樣,但都是是用於c非同步回撥或者類之間的通訊。本質上是一段可執行的函式程式碼,也可以看做是一種特殊的資料型別.

基礎定義

我們先來回顧一下OC中的Block定義和寫法,基礎寫法:
<pre><code>`

int (^addBlock)(int a,int b)=^(int a,int b){
        return a+b;
 };
 NSLog(@"FlyElephant-addBlock的結果:%d",addBlock(90,72));`</code></pre>

Swift中閉包寫法:
<pre><code>let addBlock:(Int,Int)->(Int) = { (a,b) in return a + b; } let addResult = addBlock(100,400)</code></pre>

對比之下,Swift取消了^的寫法, 通過in來區分引數和執行程式碼塊,寫的時候我們會看到將引數和in放在同一行的寫法:
<pre><code>let addBlock:(Int,Int)->(Int) = { (a,b) in return a + b; }</code></pre>
OC中我們可以通過typedef將常用的Block進行抽取,Swift中我們可以通過typealias來實現:
<pre><code>`
typealias CompleteBlock = (Int,Int)->(Int);

    let complete:CompleteBlock = { (a,b) in
        return a-b;
    }`</code></pre>

特殊閉包

專案中Block涉及最多的地方就是網路請求,從網路請求資料,成功和失敗都會通過相應的Block來實現專案狀態的變更:
網路請求:
<pre><code>`
func requestData1(urlString:String,succeed: ((Any?)->(Void))?){

    let request = URLRequest(url: URL(string: urlString)!);
    //傳送網路請求
    NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue()) { (_, data, error) in
        if error == nil {
            succeed?(data);
        }
    }
}`</code></pre>

網路請求呼叫:
<pre><code>requestData1(urlString: "") { (data) -> (Void) in print("網路請求回撥") }</code></pre>

這個是最常見的網路請求閉包非同步回撥,不過其中有一個細節需要注意的,當閉包作為函式的最後一個引數時,可以省略前面的括號,也就是常說的尾隨閉包,沒什麼特殊的作用,但是會增加程式碼的易讀性和語法簡潔性.

大家應該多少聽說過逃逸閉包,名字聽起來有點唬人,閉包更多的時候是非同步回撥,通過是函式執行完成,閉包裡面的程式碼還沒有執行,所以需要逃逸才能執行稍後的回撥.

逃逸閉包需要,加入@escaping關鍵字,上面的網路請求可以寫成以下方式:
<pre><code>`
func requestData1(urlString:String,succeed: @escaping ((Any?)->(Void))){

    let request = URLRequest(url: URL(string: urlString)!);
    //傳送網路請求
    NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue()) { (_, data, error) in
        if error == nil {
            succeed(data);
        }
    }
}`</code></pre>

最上面的網路回撥是閉包可選型別,不是閉包型別,所以可以不加入@escaping關鍵字.