Swift逃逸閉包费什、非逃逸閉包(@escaping & @noescape)

前言

很多剛開始寫Swift的同學(xué)或許已經(jīng)把閉包應(yīng)用在很多地方了,也總是會(huì)把閉包跟OC中的block劃等號(hào)解幽,的確Swift中的的閉包跟OC中的block有很多相似之處,但是Swift畢竟是一門新的語言烘苹,出于性能躲株、內(nèi)存優(yōu)化等原因的考慮,Swift比起OC而言在很多地方是有區(qū)別镣衡。以閉包來說霜定,Swift 的閉包分為 逃逸非逃逸 兩種吞琐。

逃逸閉包

概念:一個(gè)接受閉包作為參數(shù)的函數(shù),逃逸閉包(可能)會(huì)在函數(shù)返回之后才被調(diào)用然爆,也就是說閉包逃離了函數(shù)的作用域
場景舉例:網(wǎng)絡(luò)請(qǐng)求請(qǐng)求結(jié)束后才調(diào)用的閉包站粟,因?yàn)榘l(fā)起請(qǐng)求后過了一段時(shí)間后這個(gè)閉包才執(zhí)行,并不一定是在函數(shù)作用域內(nèi)執(zhí)行

func requestData() -> () {
        CCNetWorkTool.sharedInstance.request(method: .POST, URLString: API_TEST parameters: nil) {[weak self] (response, isSuccess) in
            // 請(qǐng)求失敗
            if isSuccess == false {
                // 失敗處理
                return
            }
            
            // 請(qǐng)求成功
            // ......
    }
非逃逸閉包

概念:一個(gè)接受閉包作為參數(shù)的函數(shù)曾雕, 閉包是在這個(gè)函數(shù)結(jié)束前內(nèi)被調(diào)用
注意:關(guān)于非逃逸的閉包有一個(gè)默認(rèn)規(guī)則:除了作為函數(shù)的即時(shí)參數(shù)傳入的閉包是非逃逸的奴烙,其他類型的都是逃逸的。

場景舉例:我們常用的masonry或者snapkit的添加約束的方法就是非逃逸的剖张,創(chuàng)建完子控件切诀,然后添加到父視圖,緊接著就是需要把約束設(shè)置好搔弄,這種情況不需要再等什么條件滿足后再來回調(diào)幅虑,所以就要求閉包馬上執(zhí)行。

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let orangeView = UIView()
        orangeView.backgroundColor = UIColor.orange
        view.addSubview(orangeView)
        
        orangeView.snp.makeConstraints { (make) in
            make.topMargin.equalTo(40)
            make.leftMargin.equalTo(10)
            make.rightMargin.equalTo(10)
            make.bottomMargin.equalTo(40)
            make.center.equalTo(view.center)
        }
    }
}

閉包為什么要分為逃逸和非逃逸

其實(shí)是為了管理內(nèi)存顾犹。閉包會(huì)強(qiáng)引用它捕獲的所有對(duì)象倒庵,比如你在閉包中訪問了當(dāng)前控制器的屬性、函數(shù)炫刷,編譯器會(huì)要求你在閉包中顯示 self 的引用(其實(shí)當(dāng)前對(duì)象的屬性擎宝、函數(shù)隱形帶了一個(gè)self參數(shù),一旦調(diào)用他們浑玛,隱形中就使用了self)绍申,這樣閉包會(huì)持有當(dāng)前對(duì)象,容易導(dǎo)致循環(huán)引用顾彰。

非逃逸閉包不會(huì)產(chǎn)生循環(huán)引用极阅,它會(huì)在函數(shù)作用域內(nèi)釋放,編譯器可以保證在函數(shù)結(jié)束時(shí)閉包會(huì)釋放它捕獲的所有對(duì)象涨享;使用非逃逸閉包的另一個(gè)好處是編譯器可以應(yīng)用更多強(qiáng)有力的性能優(yōu)化筋搏,例如,當(dāng)明確了一個(gè)閉包的生命周期的話灰伟,就可以省去一些保留(retain)和釋放(release)的調(diào)用拆又;此外非逃逸閉包它的上下文的內(nèi)存可以保存在棧上而不是堆上。

綜上所述栏账,如果沒有特別需要帖族,開發(fā)中使用非逃逸閉包是有利于內(nèi)存優(yōu)化的,所以蘋果把閉包區(qū)分為兩種挡爵,特殊情況時(shí)再使用逃逸閉包

Swift3.0之后怎么允許一個(gè)閉包參數(shù)逃逸

Swift3.0之前閉包作為即時(shí)函數(shù)的參數(shù)默認(rèn)為逃逸的(@escaping)竖般,但是很多開發(fā)者在開發(fā)中總是忽略去判斷閉包是否為逃逸,這樣就都被當(dāng)做了逃逸閉包處理茶鹃,對(duì)閉包的內(nèi)存管理優(yōu)化不太友好涣雕。Swift3.0中做出調(diào)整艰亮,所有作為即時(shí)函數(shù)的參數(shù)的閉包默認(rèn)是非逃逸( @noescape)。如果開發(fā)者想使閉包具有逃逸性挣郭,需要用@escaping修飾閉包迄埃,@escaping 標(biāo)識(shí)符還有警示開發(fā)者的作用,警示開發(fā)者這是一個(gè)逃逸閉包兑障,注意循環(huán)引用問題侄非,比如下面的代碼


逃逸閉包1.png

以下是幾個(gè)GCD的API用到了逃逸閉包

public func __dispatch_after(_ when: dispatch_time_t, _ queue: DispatchQueue, _ block: @escaping () -> Swift.Void)

public func __dispatch_barrier_async(_ queue: DispatchQueue, _ block: @escaping () -> Swift.Void)
注意

可選型的閉包總是逃逸的:更令人驚訝的是,即便閉包被用作參數(shù)流译,但是當(dāng)閉包被包裹在其他類型(例如元組逞怨、枚舉的 case 以及可選型)中的時(shí)候,閉包仍舊是逃逸的福澡。由于在這種情況下閉包不再是即時(shí)的參數(shù)叠赦,它會(huì)自動(dòng)變成逃逸閉包。

參考資料:
http://www.reibang.com/p/120069d493f5
http://swift.gg/2016/11/15/optional-non-escaping-closures/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末革砸,一起剝皮案震驚了整個(gè)濱河市除秀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌业岁,老刑警劉巖鳞仙,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異笔时,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)仗岸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門允耿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扒怖,你說我怎么就攤上這事较锡。” “怎么了盗痒?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蚂蕴,是天一觀的道長。 經(jīng)常有香客問我俯邓,道長骡楼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任稽鞭,我火速辦了婚禮鸟整,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朦蕴。我一直安慰自己篮条,他們只是感情好弟头,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涉茧,像睡著了一般赴恨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伴栓,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天嘱支,我揣著相機(jī)與錄音,去河邊找鬼挣饥。 笑死除师,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扔枫。 我是一名探鬼主播汛聚,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼短荐!你這毒婦竟也來了倚舀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤忍宋,失蹤者是張志新(化名)和其女友劉穎痕貌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體糠排,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舵稠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了入宦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哺徊。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖乾闰,靈堂內(nèi)的尸體忽然破棺而出落追,到底是詐尸還是另有隱情,我是刑警寧澤涯肩,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布轿钠,位于F島的核電站,受9級(jí)特大地震影響病苗,放射性物質(zhì)發(fā)生泄漏疗垛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一铅乡、第九天 我趴在偏房一處隱蔽的房頂上張望继谚。 院中可真熱鬧,春花似錦、人聲如沸花履。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诡壁。三九已至济瓢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間妹卿,已是汗流浹背旺矾。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夺克,地道東北人箕宙。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像铺纽,于是被迫代替她去往敵國和親柬帕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容