溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

defer如何在swift中使用

發(fā)布時(shí)間:2021-01-05 14:36:10 來(lái)源:億速云 閱讀:128 作者:Leah 欄目:開(kāi)發(fā)技術(shù)

defer如何在swift中使用?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。

defer語(yǔ)句在代碼塊(方法、閉包等,可以理解為大括號(hào)包裝起來(lái)的代碼)作用域退出之前\color{red}{作用域退出之前}作用域退出之前執(zhí)行,也就是代碼塊中其他應(yīng)該執(zhí)行的代碼都執(zhí)行完了,才執(zhí)行defer中的代碼

一個(gè)代碼塊允許多個(gè)defer,多個(gè)defer執(zhí)行的順序從后到前\color{red}{從后到前}從后到前

一些測(cè)試及誤區(qū)糾正

測(cè)試案例1

func testDefer() {
 defer {
 print("方法中defer內(nèi)容")
 }
 if true {
 defer {
  print("if 中defer內(nèi)容")
 }
 print("if中最后的代碼")
 }
 print("方法中的代碼")
 if true {
 return
 }
 print("方法結(jié)束前最后一句代碼")
}
testDefer()

以上代碼打印結(jié)果:

if中最后的代碼
if 中defer內(nèi)容
方法中的代碼
方法中defer內(nèi)容

打印結(jié)果中,第一個(gè)if中的代碼及里面的defer最先執(zhí)行,方法中的defer最后執(zhí)行,由此可以看出,代碼塊中其他能夠執(zhí)行的代碼先執(zhí)行,最后執(zhí)行defer的內(nèi)容;defer的作用范圍不能簡(jiǎn)單的看成方法,而是代碼塊(可能有些同學(xué)會(huì)有這樣的誤區(qū))

測(cè)試案例2

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

打印結(jié)果

開(kāi)始
defer 2 中的內(nèi)容
defer 1 中的內(nèi)容

我們可以看到最后一個(gè)defer沒(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()
 }
 
 doSomething()
}
testDefer()

在加鎖后立刻用defer解鎖,避免忘記解鎖

場(chǎng)景3:處理一些代碼塊作用域結(jié)束前的重復(fù)操作,比如請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)的時(shí)候

通常的一種寫法

func loadCityList(_ finish: ((Error?, [String]?) -> ())?) {
 DispatchQueue.global().async { // 模擬網(wǎng)絡(luò)請(qǐng)求
 let data: AnyObject? // 模擬服務(wù)器返回的數(shù)據(jù)
 guard let dict = data as? [String: AnyObject] else {
  DispatchQueue.main.async {
  finish?(error, nil)
  }
  return
 }
 guard let code = dict["code"] as? Int, code == 200 else {
  DispatchQueue.main.async {
  finish?(error, nil)
  }
  return
 }
 guard let citys = dict["data"] as? [String]? else {
  DispatchQueue.main.async {
  finish?(error, nil)
  }
  return
 }
 DispatchQueue.main.async {
  finish?(nil, citys)
 }
 }
}

當(dāng)每次有錯(cuò)誤處理時(shí)和結(jié)果正確時(shí)都需要去做回調(diào),而且回調(diào)可能有一堆代碼,看起來(lái)代碼會(huì)比較冗余,而且在一些錯(cuò)誤處理時(shí)很容易造成忘記回調(diào)

defer怎么去寫呢

func loadCityList(_ finish: ((Error?, [String]?) -> ())?) {
 DispatchQueue.global().async { // 模擬網(wǎng)絡(luò)請(qǐng)求
 var error: Error? = nil
 var citys: [String]? = nil
 defer {
  DispatchQueue.main.async {
  finish?(error, citys)
  }
 }
 
 let data: AnyObject? // 模擬服務(wù)器返回的數(shù)據(jù)
 guard let dict = data as? [String: AnyObject] else {
  error = ...
  return
 }
 guard let code = dict["code"] as? Int, code == 200 else {
  error = ...
  return
 }
 guard let tempCitys = dict["data"] as? [String]? else {
  error = ...
  return
 }
 citys = tempCitys
 }
}

使用defer既解決了代碼冗余,又解決了可能忘記回調(diào)的問(wèn)題,還有當(dāng)我們看到defer時(shí),我們很清楚知道,無(wú)論網(wǎng)絡(luò)請(qǐng)求結(jié)果如果,都會(huì)回調(diào)

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI