非逃逸閉包
非逃逸閉包的生命周期:
- 把閉包作為參數(shù)傳遞給函數(shù)。
- 函數(shù)中運行該閉包余掖。
- 退出函數(shù)鲫凶。
非逃逸閉包被限制在函數(shù)內(nèi)禀崖,當(dāng)函數(shù)退出時,該閉包的引用計數(shù)不會增加螟炫,也就是說其引用計數(shù)在進入函數(shù)和退出函數(shù)時保持不變波附。
逃逸閉包
- 閉包作為參數(shù)傳遞給函數(shù);
- 退出函數(shù)昼钻;
- 閉包被調(diào)用掸屡,閉包生命周期結(jié)束
閉包參數(shù)默認是非逃逸類型。如果需要其逃逸類型的閉包然评,可以使用關(guān)鍵字@escaping
舉個例子我們常用的Masonry或者SnapKit的添加約束的方法就是非逃逸的仅财。因為這閉包馬上就執(zhí)行了。
比如這個Alamofire里的處理返回json的completionHandler閉包就是逃逸的碗淌,網(wǎng)絡(luò)請求結(jié)束后的回調(diào)的閉包是逃逸的盏求,因為發(fā)起請求后過了一段時間后這個閉包才執(zhí)行。
//這是一個非逃逸閉包亿眠,閉包closure 在函數(shù)執(zhí)行的時候就調(diào)用了
func callAction(closure:(() -> Void)) {
closure()
}
//這是一個逃逸閉包碎罚,閉包closure 到了另一個作用域,跟當(dāng)前函數(shù)是異步的,逃逸閉包必須用@escaping來修飾纳像。因為默認是 @noescaping
func callAction(closure:@escaping (() -> Void)) {
DispatchQueue.main.async {
closure()
}
}
逃逸閉包使用場景
異步調(diào)用:如果需要調(diào)度隊列中異步調(diào)用閉包荆烈,這個隊列會持有閉包的引用,至于什么時候調(diào)用閉包竟趾,或者閉包什么時候運行結(jié)束都是不可預(yù)知的憔购。
存儲:需要存儲閉包作為屬性,全局變量或者其他類型做稍后使用。
為什么要分逃逸閉包和非逃逸閉包
為了管理內(nèi)存,閉包會強引用它捕獲的所有對象梢卸,比如你在閉包中訪問了當(dāng)前控制器的屬性、函數(shù)鞋邑,編譯器會要求你在閉包中顯示 self 的引用诵次,這樣閉包會持有當(dāng)前對象,容易導(dǎo)致循環(huán)引用枚碗。
非逃逸閉包不會產(chǎn)生循環(huán)引用逾一,它會在函數(shù)作用域內(nèi)釋放,編譯器可以保證在函數(shù)結(jié)束時閉包會釋放它捕獲的所有對象肮雨;使用非逃逸閉包的另一個好處是編譯器可以應(yīng)用更多強有力的性能優(yōu)化遵堵,例如,當(dāng)明確了一個閉包的生命周期的話怨规,就可以省去一些保留(retain)和釋放(release)的調(diào)用陌宿;此外非逃逸閉包它的上下文的內(nèi)存可以保存在棧上而不是堆上。
綜上所述波丰,如果沒有特別需要壳坪,開發(fā)中使用非逃逸閉包是有利于內(nèi)存優(yōu)化的,所以蘋果把閉包區(qū)分為兩種掰烟,特殊情況時再使用逃逸閉包爽蝴。