亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Swift > 正文

Swift中defer的正確使用方法

2020-03-09 17:31:16
字體:
來源:轉載
供稿:網友

defer 是干什么用的

很簡單,用一句話概括,就是 defer block 里的代碼會在函數 return 之前執行,無論函數是從哪個分支 return 的,還是有 throw,還是自然而然走到最后一行。

這個關鍵字就跟 Java 里的 try-catch-finally 的finally一樣,不管 try catch 走哪個分支,它都會在函數 return 之前執行。而且它比 Java 的finally還更強大的一點是,它可以獨立于 try catch 存在,所以它也可以成為整理函數流程的一個小幫手。在函數 return 之前無論如何都要做的處理,可以放進這個 block 里,讓代碼看起來更干凈一些~

其實這篇文章的緣起是由于在對 Kingfisher 做重構的時候,因為自己對 defer 的理解不夠準確,導致了一個 bug。所以想藉由這篇文章探索一下 defer 這個關鍵字的一些 edge case。

典型用法

Swift 里的 defer 大家應該都很熟悉了,defer 所聲明的 block 會在當前代碼執行退出后被調用。正因為它提供了一種延時調用的方式,所以一般會被用來做資源釋放或者銷毀,這在某個函數有多個返回出口的時候特別有用。比如下面的通過 FileHandle 打開文件進行操作的方法:

func operateOnFile(descriptor: Int32) {let fileHandle = FileHandle(fileDescriptor: descriptor)let data = fileHandle.readDataToEndOfFile()if /* onlyRead */ {fileHandle.closeFile()return}let shouldWrite = /* 是否需要寫文件 */guard shouldWrite else {fileHandle.closeFile()return}fileHandle.seekToEndOfFile()fileHandle.write(someData)fileHandle.closeFile()}

我們在不同的地方都需要調用 fileHandle.closeFile() 來關閉文件,這里更好的做法是用 defer 來統一處理。這不僅可以讓我們就近在資源申請的地方就聲明釋放,也減少了未來添加代碼時忘記釋放資源的可能性:

func operateOnFile(descriptor: Int32) {let fileHandle = FileHandle(fileDescriptor: descriptor)defer { fileHandle.closeFile() }let data = fileHandle.readDataToEndOfFile()if /* onlyRead */ { return }let shouldWrite = /* 是否需要寫文件 */guard shouldWrite else { return }fileHandle.seekToEndOfFile()fileHandle.write(someData)}

defer 的作用域

在做 Kingfisher 重構時,對線程安全的保證我選擇使用了 NSLock 來完成。簡單說,會有一些類似這樣的方法:

let lock = NSLock()let tasks: [ID: Task] = [:]func remove(_ id: ID) {lock.lock()defer { lock.unlock() }tasks[id] = nil}

對于 tasks 的操作可能發生在不同線程中,用 lock() 來獲取鎖,并保證當前線程獨占,然后在操作完成后使用 unlock() 釋放資源。這是很典型的 defer 的使用方式。

但是后來出現了一種情況,即調用 remove 方法之前,我們在同一線程的 caller 中獲取過這個鎖了,比如:

func doSomethingThenRemove() {lock.lock()defer { lock.unlock() }// 操作 `tasks`// ...// 最后,移除 `task`remove(123)}

這樣做顯然在 remove 中造成了死鎖 (deadlock):remove 里的 lock() 在等待 doSomethingThenRemove 中做 unlock() 操作,而這個 unlock 被 remove 阻塞了,永遠不可能達到。

解決的方法大概有三種:

  1. 換用 NSRecursiveLock:NSRecursiveLock 可以在同一個線程獲取多次,而不造成死鎖的問題。
  2. 在調用 remove 之前先 unlock。
  3. 為 remove 傳入按照條件,避免在其中加鎖。

1 和 2 都會造成額外的性能損失,雖然在一般情況下這樣的加鎖性能微乎其微,但是使用方案 3 似乎也并不很麻煩。于是我很開心地把 remove 改成了這樣:

func remove(_ id: ID, acquireLock: Bool) {if acquireLock {lock.lock()defer { lock.unlock() }}tasks[id] = nil}

很好,現在調用 remove(123, acquireLock: false) 不再會死鎖了。但是很快我發現,在 acquireLock 為 true 的時候鎖也失效了。再仔細閱讀 Swift Programming Language 關于 defer 的描述:

A defer statement is used for executing code just before transferring program control outside of the scope that the defer statement appears in.

所以,上面的代碼其實相當于:

func remove(_ id: ID, acquireLock: Bool) {if acquireLock {lock.lock()lock.unlock()}tasks[id] = nil}

GG 斯密達…

以前很單純地認為 defer 是在函數退出的時候調用,并沒有注意其實是當前 scope 退出的時候調用這個事實,造成了這個錯誤。在 if,guard,for,try 這些語句中使用 defer 時,應該要特別注意這一點。

defer 和閉包

另一個比較有意思的事實是,雖然 defer 后面跟了一個閉包,但是它更多地像是一個語法糖,和我們所熟知的閉包特性不一樣,并不會持有里面的值。比如:

func foo() {var number = 1defer { print("Statement 2: /(number)") }number = 100print("Statement 1: /(number)")}

將會輸出:

Statement 1: 100
Statement 2: 100

在 defer 中如果要依賴某個變量值時,需要自行進行復制:

func foo() {var number = 1var closureNumber = numberdefer { print("Statement 2: /(closureNumber)") }number = 100print("Statement 1: /(number)")}// Statement 1: 100// Statement 2: 1

defer 的執行時機

defer 的執行時機緊接在離開作用域之后,但是是在其他語句之前。這個特性為 defer 帶來了一些很“微妙”的使用方式。比如從 0 開始的自增:

class Foo {var num = 0func foo() -> Int {defer { num += 1 }return num}// 沒有 `defer` 的話我們可能要這么寫// func foo() -> Int {// num += 1// return num - 1// }}let f = Foo()f.foo() // 0f.foo() // 1f.num // 2

輸出結果 foo() 返回了 +1 之前的 num,而 f.num 則是 defer 中經過 +1 之后的結果。不使用 defer 的話,我們其實很難達到這種“在返回后進行操作”的效果。

雖然很特殊,但是強烈不建議在 defer 中執行這類 side effect。

This means that a defer statement can be used, for example, to perform manual resource management such as closing file descriptors, and to perform actions that need to happen even if an error is thrown.

從語言設計上來說,defer 的目的就是進行資源清理和避免重復的返回前需要執行的代碼,而不是用來以取巧地實現某些功能。這樣做只會讓代碼可讀性降低。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到swift教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲高清一区二| 久久成人一区二区| 欧美精品在线观看| 中文字幕亚洲在线| 91精品国产综合久久香蕉922| 亚洲免费视频观看| 国产欧美精品一区二区| 久久久久亚洲精品| 欧美亚洲第一区| 日韩免费av片在线观看| 秋霞成人午夜鲁丝一区二区三区| 一本色道久久88综合亚洲精品ⅰ| 国产精品久久中文| 欧美高跟鞋交xxxxhd| 亚洲精品国产精品国自产观看浪潮| 欧美成人全部免费| 91九色蝌蚪国产| 色av中文字幕一区| 久久久久这里只有精品| 亚洲va电影大全| 欧美日韩午夜剧场| 欧美日韩在线观看视频小说| 欧美日韩aaaa| 色噜噜狠狠狠综合曰曰曰| 欧美限制级电影在线观看| 宅男66日本亚洲欧美视频| 欧美成人精品一区| 亚洲精品自拍视频| 国产精品国语对白| 日韩av最新在线| 日韩中文第一页| 亚洲免费人成在线视频观看| 精品视频一区在线视频| 久久综合国产精品台湾中文娱乐网| 热re99久久精品国产66热| 久久人人爽人人爽人人片av高清| 亚洲欧美一区二区激情| 国产精品欧美一区二区三区奶水| 亚洲国产日韩欧美在线图片| 日韩av免费看网站| 日韩中文字幕国产| 久久久亚洲影院你懂的| 日韩免费看的电影电视剧大全| 国产成人免费91av在线| 成人信息集中地欧美| 亚洲国产精品一区二区三区| 亚洲图中文字幕| 欧美激情免费视频| 97在线精品国自产拍中文| 青青草国产精品一区二区| 色偷偷av一区二区三区乱| 黄色成人在线播放| 欧美精品videosex牲欧美| 91精品国产综合久久香蕉的用户体验| 91精品国产91久久久久福利| 深夜精品寂寞黄网站在线观看| 欧美国产极速在线| 欧美国产日韩一区二区| 2020国产精品视频| 亚洲男人的天堂网站| 欧美精品电影免费在线观看| 91亚洲va在线va天堂va国| 国产精品高潮呻吟久久av野狼| 日韩精品日韩在线观看| 久久精品一区中文字幕| 欧美成人免费在线视频| 亚洲男人天堂古典| 欧美视频在线免费| 在线精品视频视频中文字幕| 欧美性做爰毛片| 国产成人精品电影久久久| 欧美诱惑福利视频| 国产精品嫩草视频| 精品国产一区久久久| 成人国产精品免费视频| 欧美视频在线观看免费网址| 久久久伊人欧美| 国产精品99久久99久久久二8| 精品免费在线视频| 亚洲第一区在线观看| 91人成网站www| 成人性生交xxxxx网站| 国产日产欧美a一级在线| 欧美精品一区二区三区国产精品| 九九久久久久久久久激情| 国模视频一区二区| 国产精品成人久久久久| 日本在线观看天堂男亚洲| 国产精品电影一区| 久久久国产精彩视频美女艺术照福利| 亚洲精品日韩久久久| 日韩中文字幕精品| 一区二区三区四区精品| 欧美精品久久久久| 国产一区二区免费| 国产精品极品尤物在线观看| 亚洲国产精品系列| 国产精品久久久久久久久久| 久久偷看各类女兵18女厕嘘嘘| 欧美另类在线观看| 欧美大肥婆大肥bbbbb| 亚洲jizzjizz日本少妇| 欧美激情免费视频| 一区二区三区无码高清视频| 欧美国产日韩中文字幕在线| 久久影视免费观看| 亚州av一区二区| 在线视频国产日韩| 欧美成人免费在线视频| 国产综合色香蕉精品| 久久成人精品电影| 成人国产精品一区| 欧美激情精品久久久| 成人激情黄色网| 亚洲欧美日韩精品| 亚洲天堂第一页| 日韩久久免费视频| 伦伦影院午夜日韩欧美限制| 欧美老妇交乱视频| 久99九色视频在线观看| 亚洲一区二区三区成人在线视频精品| 一区二区三区www| 久久精品91久久香蕉加勒比| 欧美视频一二三| 中文字幕日韩专区| 日韩精品中文字幕在线观看| 精品国产乱码久久久久久婷婷| 日韩av电影在线网| 欧美激情在线观看| 欧美日韩中文在线观看| 亚洲a在线播放| 亚洲精品资源在线| 日韩av手机在线| 久久男人资源视频| 亚洲人成自拍网站| 清纯唯美日韩制服另类| 日韩欧美国产视频| 国产欧美精品在线| 成人性生交大片免费看视频直播| 日韩最新中文字幕电影免费看| 青青在线视频一区二区三区| 亚洲一区二区福利| 92版电视剧仙鹤神针在线观看| 国产精品视频导航| 亚洲国产99精品国自产| 国产精品一区=区| 亚洲精品国产成人| 中文字幕亚洲自拍| 欧美国产日韩免费| 日韩久久精品成人| 在线观看久久久久久| 久久青草精品视频免费观看| 欧美激情在线播放| 国产精品扒开腿爽爽爽视频| 亚洲精品美女免费| 一区二区三区高清国产| 国产精品久久久久久久久久ktv| 国产综合在线观看视频| 午夜精品久久久久久久男人的天堂| 国产精品视频不卡| 亚洲综合精品伊人久久| 欧美激情视频在线免费观看 欧美视频免费一| 成人97在线观看视频| 在线观看成人黄色|