Swift閉包、閉包簡寫、尾隨閉包、逃逸閉包、自動閉包

閉包介紹

Swift閉包和Objective-C中的Block很類似,是一段自包含的函數(shù)代碼塊,可以在代碼中使用和傳遞。相當(dāng)于一個匿名函數(shù)。
函數(shù):是一個有名字的閉包。
普通函數(shù):是一個有名字但不會捕獲任何值的閉包。
嵌套函數(shù):是一個有名字并可以捕獲其封閉函數(shù)域內(nèi)值的閉包。

閉包格式

閉包表達(dá)式語法有如下的一般形式:

{ (parameters) -> returnType in
    statements
}
閉包使用、尾隨閉包、閉包簡寫格式
// 以下閉包以Array的sorted函數(shù)為例
    func testClosure() {
        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})
       
        // 單行表達(dá)式:可以去掉return
        reversedNames = names.sorted(by: {str1, str2 in str1 > str2})
        
        // 使用參數(shù)名縮寫:參數(shù)和in也可以去掉
        reversedNames = names.sorted(by: {$0 > $1})
       
        // 使用運(yùn)算符:因?yàn)镾wift中為字符串重載了大于號小于號
        reversedNames = names.sorted(by: >)
        
        // 使用尾隨閉包:前提是閉包必須是函數(shù)的最后一個參數(shù)
        reversedNames = names.sorted() {$0 < $1}
        
        // 使用尾隨閉包:閉包是函數(shù)唯一參數(shù)時,可以省掉參數(shù)括號
        reversedNames = names.sorted {$0 < $1}
        
        print(reversedNames)
    }

閉包值捕獲,閉包是引用類型

先貼代碼:

// 值捕獲示例:下面嵌套函數(shù)incrementer本身沒有參數(shù),它卻捕獲了外圍的參數(shù)runningTotal和amount
    func makeIncrementer(forIncrement amount: Int) -> () -> Int {
        var runningTotal = 0
        func incrementer() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementer
    }

// 調(diào)用
let makeIncrementByTen = makeIncrementer(forIncrement: 10)
        var ret = makeIncrementByTen()
        print("ret= \(ret)")// ret= 10
        ret = makeIncrementByTen()
        print("ret= \(ret)")// ret= 20
        ret = makeIncrementByTen()
        print("ret= \(ret)")// ret= 30
        
        let makeIncrementBySeven = makeIncrementer(forIncrement: 7)
        ret = makeIncrementBySeven()
        print("ret= \(ret)")// ret= 7
        
        ret = makeIncrementByTen()
        print("ret= \(ret)")// ret= 40
        
        // 上面的同一個閉包連續(xù)調(diào)用,值會遞增原因:閉包是引用類型,同一個閉包捕獲的變量并沒有釋放

逃逸閉包

逃逸閉包概念:當(dāng)一個閉包作為參數(shù)傳到一個函數(shù)中,但是這個閉包在函數(shù)返回之后才被執(zhí)行,我們稱該閉包從函數(shù)中逃逸。逃逸閉包多用來做函數(shù)回調(diào),與Objective-C里的Block有異曲同工之妙。
代碼示例:

// 逃逸閉包示例:下面的閉包被方法外的數(shù)組引用,也就意味著,這個閉包在函數(shù)執(zhí)行完后還可能被調(diào)用,所以必須使用逃逸閉包,不然編譯不過去
    var completionHandlers: [() -> Void] = []
    func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
        completionHandlers.append(completionHandler)
    }
// 非逃逸閉包
    func someFunctionWithNoneEscapingClosure(closure: () -> Void) {
        closure()
    }

    var x = 10
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib. 
        // 逃逸閉包
        someFunctionWithEscapingClosure {
            // 注意:逃逸閉包類必須顯式的引用self,
            self.x = 100
        }
        someFunctionWithNoneEscapingClosure {
            x = 200
        }
        print("x= \(x)")// x= 200
        completionHandlers.first?()
        print("x= \(x)")// x= 100
    }

自動閉包

自動閉包:閉包作為參數(shù)傳遞給函數(shù)時,可以將閉包定義為自動閉包(使用關(guān)鍵字@autoclosure)。這樣傳遞參數(shù)時,可以直接傳遞一段代碼(或者一個變量、表達(dá)式),系統(tǒng)會自動將這段代碼轉(zhuǎn)化成閉包。需要注意:過度使用 autoclosures 會讓你的代碼變得難以理解。這里不貼代碼了。

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

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

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