Swift-閉包

  • 閉包是自包含的功能代碼塊,可以在代碼中使用或者用來作為參數(shù)傳值。
  • 在Swift中的閉包與OC中的block類似。
 //閉包的表達式語法
/*
{(parameters) ->(return type) in
    statements
}
*/

//對整數(shù)進行排序 sorted 后面就是閉包
let numbers = [1, 5, 9, 6, 2, 3, 4]
let newNumbers = numbers.sorted { (a, b) -> Bool in
    return a > b
}
print(newNumbers)  //結(jié)果是 [9, 6, 5, 4, 3, 2, 1]
  • 全局函數(shù)和嵌套函數(shù)其實就是特殊的閉包。
//設(shè)置全局方法獲取某些值
func kNaviBarHeight() -> Float {
    return 44
}

print(kNaviBarHeight())
  • 閉包的形式有:
  • (1)全局函數(shù)都是閉包,有名字但不能捕獲任何值。
  • (2)嵌套函數(shù)都是閉包,且有名字,也能捕獲封閉函數(shù)內(nèi)的值。
  • (3)閉包表達式都是無名閉包,使用輕量級語法,可以根據(jù)上下文環(huán)境捕獲值。
  • Swift中的閉包有很多優(yōu)化的地方:
  • (1)根據(jù)上下文推斷參數(shù)和返回值類型
  • (2)從單行表達式閉包中隱式返回(也就是閉包體只有一行代碼,可以省略return)
  • (3)可以使用簡化參數(shù)名,如$0, $1(從0開始,表示第i個參數(shù)...)
  • (4)提供了尾隨閉包語法(Trailing closure syntax)
    */
// 以下閉包以Array的sorted函數(shù)為例
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backward(_ str1: String, _ str2: String) -> Bool {
    return str1 > str2
}

// sorted函數(shù)的參數(shù)是一個閉包,下面?zhèn)髁艘粋€方法名,由此說明:嵌套函數(shù)是一個有名字但并可以捕獲其封閉函數(shù)域內(nèi)值的閉包
var reversedNames = names.sorted(by: backward)

// 普通閉包格式:(參數(shù): 參數(shù)類型,...) -> 返回值類型 in ...
reversedNames = names.sorted(by: { (str1: String, str2: String) -> Bool in
    return str1 > str2
})

// 根據(jù)Swift的類型推斷,參數(shù)類型及參數(shù)括號可以去掉,返回值類型可以去掉
reversedNames = names.sorted(by: { str1, str2 in
    return str1 > str2
})

// 單行表達式:可以去掉return
reversedNames = names.sorted(by: {str1, str2 in
    str1 > str2
})

// 使用參數(shù)名縮寫:參數(shù)和in也可以去掉
reversedNames = names.sorted(by: {
    $0 > $1     //$0代表第1個參數(shù), $1 代表第二個參數(shù)
})

// 使用運算符:因為Swift中為字符串重載了大于號小于號
reversedNames = names.sorted(by: >)

// 使用尾隨閉包:前提是閉包必須是函數(shù)的最后一個參數(shù)
reversedNames = names.sorted() {$0 < $1}

// 使用尾隨閉包:閉包是函數(shù)唯一參數(shù)時,可以省掉參數(shù)括號
reversedNames = names.sorted {$0 < $1}

print(reversedNames)
  • 閉包值捕獲,閉包是引用類型
//sum 返回值是一個閉包 () -> Int
func sum(amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        print("runningTotal = \(runningTotal)")
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let addByTen = sum(amount: 10)

print("結(jié)果 \(addByTen())")
print("結(jié)果 \(addByTen())")

//打印結(jié)果
/*
runningTotal = 0
結(jié)果 10
runningTotal = 10
結(jié)果 20
*/
//兩次調(diào)用incrementer閉包是同一個 runningTotal 被保留下來,所以閉包是引用類型的
  • 逃逸閉包和非逃逸閉包
    如果這個閉包是在這個函數(shù)結(jié)束前內(nèi)被調(diào)用,就是非逃逸的即noescape。
    如果這個閉包是在函數(shù)執(zhí)行完后才被調(diào)用,調(diào)用的地方超過了這函數(shù)的范圍,所以叫逃逸閉包。

例如:snapkit的添加約束的方法就是非逃逸的。因為這閉包馬上就執(zhí)行了

public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
        ConstraintMaker.makeConstraints(item: self.view, closure: closure)
    }

網(wǎng)絡(luò)請求請求結(jié)束后的回調(diào)的閉包則是逃逸的,因為發(fā)起請求后過了一段時間后這個閉包才執(zhí)行。比如這個Alamofire里的處理返回json的completionHandler閉包,就是逃逸的。

 public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
        delegate.queue.addOperation {
            (queue ?? DispatchQueue.main).async {
                var dataResponse = DefaultDataResponse(
                    request: self.request,
                    response: self.response,
                    data: self.delegate.data,
                    error: self.delegate.error,
                    timeline: self.timeline
                )

                dataResponse.add(self.delegate.metrics)

                completionHandler(dataResponse)
            }
        }

        return self
    }

舉個例子,寫一個模擬一個網(wǎng)絡(luò)請求,1秒才執(zhí)行,所以是逃逸閉包。

//此處編譯不通過
 func loadRequest(callBack: () -> Void) -> Void {
        DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 1) {
            callBack()
        }
    }

//下面是正確的寫法
func loadRequest(callBack: @escaping () -> Void) -> Void {
        DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 1) {
            callBack()
        }
    }

這樣就需要顯示的聲明@escaping才能編譯通過。

AD743289-18E8-43BC-8131-9B0C5D4A50C6.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

  • 閉包是自包含的函數(shù)代碼塊,可以在代碼中被傳遞和使用。Swift 中的閉包與 C 和 Objective-C 中的代...
    窮人家的孩紙閱讀 1,811評論 1 5
  • 閉包可以從定義它們的上下文中捕獲和存儲對任何常量和變量的引用。 這被稱為關(guān)閉這些常量和變量。 Swift處理所有的...
    Joker_King閱讀 638評論 0 2
  • Swift 中的閉包是自包含的函數(shù)代碼塊,可以在代碼中被傳遞和使用。類似于OC中的Block以及其他函數(shù)的匿名函數(shù)...
    喬克_叔叔閱讀 556評論 1 3
  • * 閉包 是自包含的函數(shù)代碼塊,可以在代碼中被傳遞和使用。swift中的閉包和Objective-C中的代碼塊(b...
    EndEvent閱讀 894評論 4 8
  • 閉包是自包含的代碼塊,可以在代碼中被傳遞和使用。Swift中的閉包與C和Objective-C中代碼塊(block...
    Raaaaamsey閱讀 906評論 0 2

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