逃逸(escaping)/非逃逸(noescape)閉包清單

本文是自己的加深理解和記憶的筆記,非原創(chuàng)。按照自己的理解習(xí)慣改寫了其他文章的內(nèi)容(引用資料在最下方),看看就好,最后強(qiáng)調(diào)一次,非原創(chuàng)。

[TOC]

1. 什么是逃逸閉包?如何標(biāo)記?

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.

即:作為一個傳入?yún)?shù),若該閉包在函數(shù)返回后才被執(zhí)行的話,則該閉包就是在逃逸函數(shù)。(這樣的閉包就是逃逸閉包。)你需要在參數(shù)前加上@escaping標(biāo)記來表明閉包是逃逸的。

2. 什么情況下使用逃逸閉包標(biāo)記?

  • 函數(shù)外存儲

    如果一個函數(shù)參數(shù)可能導(dǎo)致引用循環(huán),那么它需要被顯示地標(biāo)記出來。@escaping標(biāo)記可以作為一個警告,來提醒使用這個函數(shù)的開發(fā)者注意引用關(guān)系。

    舉個例子。此時的callbackself所持有,典型的可能在函數(shù)return之后被執(zhí)行。

    class SomeClass {
        var callback:(()->Void)?
        func doSomething(callback:@escaping ()->Void) { // 加上逃逸修飾詞
            self.callback = callback  
       }
    }
    
  • 異步調(diào)用

    同理,如果閉包被放進(jìn)async dispatch queue,則該閉包也會被queue retain,同樣可能在函式結(jié)束后才被執(zhí)行,因此也算是“逃逸”

    舉個例子。此時的callback被異步調(diào)用了

    class SomeClass {
        func doWorkAsync(block: @escaping () -> ()) { // 加上逃逸修飾詞
            DispatchQueue.main.async {
                block() 
            }
        }
    }
    

3. 非逃逸閉包有什么限制

  • 不能在函式外儲存

  • 不能進(jìn)async dispatch queue

  • 不能作為其他逃逸閉包函數(shù)的參數(shù)

    把@noescape閉包傳到其他@noescape參數(shù)是可以的,一連串不會逃逸的傳值,最終還是不會逃逸(下面的@noescape會被編譯器提示刪除,因?yàn)閟wift3開始默認(rèn)的就是非逃逸閉包)

    class SomeClass {
        func foo( code:@noescape (() -> String)) -> String {
            return bar(code: code)
        }
        func bar( code:@noescape (() -> String)) -> String {
            return code()
        }
    }
    

4.其他:

  • 從swift3開始,閉包默認(rèn)為非逃逸閉包。之前則相反,且使用@noescape進(jìn)行標(biāo)記(此標(biāo)記已廢棄)。

  • 非逃逸閉包可用被編譯器高度優(yōu)化,快速的執(zhí)行路徑將被作為基準(zhǔn)而使用,除非你在有需要的時候顯式地使用其他方法。

  • 和弱引用關(guān)系:非逃逸閉包中可放心使用self關(guān)鍵字,因?yàn)椴粫诤瘮?shù)外儲存,也不會被異步調(diào)用。你不需要去使用一個弱引用(weak或unowned)去引用self。

  • 在函數(shù)內(nèi)部儲存閉包也會被識別成逃逸,雖然并不會(現(xiàn)在的最新swift4仍存在這個問題)

    func doSomething(callback:(()->Void) {
        let c = callback // error: non-escaping parameter 'callback' may only be called
        c()
    }
    

引用資料:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。