Swift 中 defer 的介紹與使用場(chǎng)景

Swift 中 defer 的介紹與使用場(chǎng)景

用defer語(yǔ)句在即將離開(kāi)當(dāng)前代碼塊時(shí)執(zhí)行一系列語(yǔ)句。該語(yǔ)句讓你能執(zhí)行一些必要的善后工作(比如偶惠,關(guān)閉,清理,回調(diào))不管是以何種方式離開(kāi)當(dāng)前代碼塊的---無(wú)論是由于拋出錯(cuò)誤而離開(kāi)献宫,或者是由于諸如return,break的語(yǔ)句实撒。

例如:你可以用defer語(yǔ)句來(lái)確保文件描述符得以關(guān)閉姊途,以及手動(dòng)分配的內(nèi)存得以釋放。

defer語(yǔ)句將代碼的執(zhí)行延遲到當(dāng)前的作用域退出之前知态。該語(yǔ)句由defer關(guān)鍵字和要被延遲的語(yǔ)句組成捷兰。延遲執(zhí)行的語(yǔ)句不能包括任何控制轉(zhuǎn)移語(yǔ)句,例如break负敏,return語(yǔ)句贡茅,或是拋出一個(gè)錯(cuò)誤,延遲執(zhí)行的操作會(huì)按照它們聲明的順序從后往前執(zhí)行---也就是說(shuō)其做,第一條defer語(yǔ)句中的代碼最后才執(zhí)行顶考,第二條defer語(yǔ)句中的代碼倒數(shù)第二個(gè)執(zhí)行,以此類推庶柿,最后一條語(yǔ)句會(huì)第一個(gè)執(zhí)行村怪。

defer 語(yǔ)句在代碼塊(方法,閉包等浮庐,可以理解為大括號(hào)包裝起來(lái)的代碼)作用域退出之前執(zhí)行甚负,也就是代碼塊中其他代碼該執(zhí)行的都執(zhí)行完了,才執(zhí)行defer中的代碼一個(gè)代碼塊允許多個(gè)defer审残,多個(gè)defer執(zhí)行的順序從后到前梭域。

測(cè)試案例1

func testDefer() {
    defer {
        print("方法中defer內(nèi)容") // 4
    }
    if true {
        defer {
            print("if 中defer內(nèi)容") // 2
        }
        print("if中最后的代碼") // 1 
    }
    print("方法中的代碼") // 3
    if true {
        return
    }
    print("方法結(jié)束前最后一句代碼") // 前面return 掉了 這里不執(zhí)行
}

testDefer()


執(zhí)行結(jié)果
if中最后的代碼
if 中defer內(nèi)容
方法中的代碼
方法中defer內(nèi)容

打印結(jié)果中,第一個(gè) if true 中的代碼塊先執(zhí)行(if中的 最后的代碼先執(zhí)行搅轿,然后是 if中的 defer 代碼塊)病涨,然后是 if下方的 方法中的代碼執(zhí)行,最后執(zhí)行testDefer方法中的 defer 代碼塊璧坟。

由此可以看出既穆,代碼塊中其他能夠執(zhí)行的代碼先執(zhí)行,最后執(zhí)行defer的內(nèi)容雀鹃;defer的作用范圍不能簡(jiǎn)單的看成方法幻工,而是代碼塊

測(cè)試案例2

func testDefer() {
    print("開(kāi)始") // 1
    defer {
        print("defer 1 中的內(nèi)容") // 4
    }
    defer {
        print("defer 2 中的內(nèi)容") // 3
    }
    print("方法中的代碼") // 2
    if true {
        return
    }
    defer {
        print("defer 3 中的內(nèi)容")
    }
    print("方法結(jié)束前最后一句代碼")
}
testDefer()

結(jié)果
開(kāi)始
方法中的代碼
defer 2 中的內(nèi)容
defer 1 中的內(nèi)容

我們可以看出 if true 之后的代碼 都沒(méi)有執(zhí)行,包括最后一個(gè) defer 3 也沒(méi)有執(zhí)行黎茎,所以defer定義的位置很重要囊颅,如果沒(méi)有執(zhí)行defer定義的代碼,在代碼塊結(jié)束前,不會(huì)執(zhí)行defer中的內(nèi)容踢代。
注意:多個(gè)defer的執(zhí)行順序從后到前

一些實(shí)際應(yīng)用場(chǎng)景

場(chǎng)景1 - 一些資源用完后需要釋放盲憎,這里給的是官方的一個(gè)案例


func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)
        }
        while let line = try file.readline() {
            // 處理文件。
        }
        // close(file) 會(huì)在這里被調(diào)用胳挎,即作用域的最后饼疙。
    }
}

開(kāi)始用到資源的時(shí)候就是用defer去釋放,避免忘記釋放資源串远。

場(chǎng)景2 - 加鎖解鎖宏多,借鑒了 kingfisher

let lock = NSLock()
func testDefer() {
    lock.lock()
    defer {
        lock.unlock()
    }
    print("doSomething。澡罚。伸但。")
}
testDefer()

在加鎖后,添加defer代碼解鎖留搔,避免忘記解鎖更胖。

場(chǎng)景3 - 處理一些代碼塊作用域結(jié)束前的重復(fù)操作,如調(diào) completion block

這是一個(gè)讓我感覺(jué)“如果當(dāng)時(shí)知道 defer ”就好了的場(chǎng)景隔显,就是有時(shí)候一個(gè)函數(shù)分支比較多却妨,可能某個(gè)小分支 return 之前就忘了調(diào) completion block,結(jié)果藏下一個(gè)不易發(fā)現(xiàn)的 bug括眠。用 defer 就可以不用擔(dān)心這個(gè)問(wèn)題了

func foo(completion: () -> Void) {
  defer {
    self.isLoading = false
    completion()
  }
  guard error == nil else { return } 
  // handle success
}

有時(shí)候 completion 要根據(jù)情況傳不同的參數(shù)彪标,這時(shí) defer 就不好使了。不過(guò)如果 completion block 被存下來(lái)了掷豺,我們還是可以用它來(lái)確保執(zhí)行后能釋放:

func foo() {
  defer {
    self.completion = nil
  }
  if (succeed) {
    self.completion(.success(result))
  } else {
    self.completion(.error(error))
  }
}

場(chǎng)景4 調(diào)用supper方法

有時(shí)候 override 一個(gè)方法捞烟, 主要目的是在super方法之前做一些準(zhǔn)備工作,我們就可以把調(diào)用 super 的部分放在 defer 里面:

func override foo() {
  defer {
    super.foo()
  }
  // some preparation before super.foo()...
}

建議:最好不要加多個(gè) defer 否則邏輯更加會(huì)顯著比較混亂当船。


大家多喝熱水题画,最近天真干。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末德频,一起剝皮案震驚了整個(gè)濱河市苍息,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌壹置,老刑警劉巖竞思,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異钞护,居然都是意外死亡盖喷,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門患亿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)传蹈,“玉大人,你說(shuō)我怎么就攤上這事步藕〉虢纾” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵咙冗,是天一觀的道長(zhǎng)沾歪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)雾消,這世上最難降的妖魔是什么灾搏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮立润,結(jié)果婚禮上狂窑,老公的妹妹穿的比我還像新娘。我一直安慰自己桑腮,他們只是感情好泉哈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著破讨,像睡著了一般丛晦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上提陶,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天烫沙,我揣著相機(jī)與錄音,去河邊找鬼隙笆。 笑死锌蓄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仲器。 我是一名探鬼主播煤率,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼乏冀!你這毒婦竟也來(lái)了蝶糯?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辆沦,失蹤者是張志新(化名)和其女友劉穎昼捍,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體肢扯,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妒茬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔚晨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乍钻。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肛循,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出银择,到底是詐尸還是另有隱情多糠,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布浩考,位于F島的核電站夹孔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏析孽。R本人自食惡果不足惜搭伤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望袜瞬。 院中可真熱鬧怜俐,春花似錦、人聲如沸邓尤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)裁赠。三九已至殿漠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間佩捞,已是汗流浹背绞幌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留一忱,地道東北人莲蜘。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像帘营,于是被迫代替她去往敵國(guó)和親票渠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

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