swift中defer的實(shí)際應(yīng)用小結(jié)
看看蘋(píng)果官方的介紹
用 defer 語(yǔ)句在即將離開(kāi)當(dāng)前代碼塊時(shí)執(zhí)行一系列語(yǔ)句。該語(yǔ)句讓你能執(zhí)行一些必要的清理工作,不管是以何種方式離開(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)鍵字和要被延遲執(zhí)行的語(yǔ)句組成。延遲執(zhí)行的語(yǔ)句不能包含任何控制轉(zhuǎn)移語(yǔ)句,例如 break、return 語(yǔ)句,或是拋出一個(gè)錯(cuò)誤。延遲執(zhí)行的操作會(huì)按照它們聲明的順序從后往前執(zhí)行——也就是說(shuō),第一條 defer 語(yǔ)句中的代碼最后才執(zhí)行,第二條 defer 語(yǔ)句中的代碼倒數(shù)第二個(gè)執(zhí)行,以此類(lèi)推。最后一條語(yǔ)句會(huì)第一個(gè)執(zhí)行。
總結(jié)一下蘋(píng)果官方的介紹
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í)候
通常的一種寫(xiě)法
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怎么去寫(xiě)呢
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)
總結(jié)
本文主要介紹了defer的定義、作用及一些用法
到此這篇關(guān)于swift中defer的實(shí)際應(yīng)用的文章就介紹到這了,更多相關(guān)swift中defer應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Swift語(yǔ)言實(shí)現(xiàn)地圖坐標(biāo)彈跳動(dòng)畫(huà)
這篇文章主要介紹了用Swift語(yǔ)言實(shí)現(xiàn)地圖坐標(biāo)彈跳動(dòng)畫(huà)的方法主要應(yīng)用iOS7來(lái)實(shí)現(xiàn)此功能,需要的朋友可以參考下2015-07-07
Swift中的類(lèi)class與結(jié)構(gòu)體struct體學(xué)習(xí)筆記
和C++一樣,Swfit中同時(shí)擁有類(lèi)與結(jié)構(gòu)體,能夠充分滿足開(kāi)發(fā)者面向?qū)ο蠛兔嫦蜻^(guò)程編程的需求,這里我們就來(lái)看一下Swift中的類(lèi)class與結(jié)構(gòu)體struct體學(xué)習(xí)筆記2016-07-07
Swift免費(fèi)短信驗(yàn)證碼實(shí)現(xiàn)及動(dòng)態(tài)倒計(jì)時(shí)功能
這篇文章主要介紹了Swift免費(fèi)短信驗(yàn)證碼實(shí)現(xiàn)及動(dòng)態(tài)倒計(jì)時(shí)功能的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02
iOS Swift讀取本地json文件報(bào)錯(cuò)的解決方法
只要是app開(kāi)發(fā)者都知道,從服務(wù)器端獲得的數(shù)據(jù)要不就是json格式的數(shù)據(jù),要么就是xml格式的數(shù)據(jù),而這篇文章主要給大家介紹了關(guān)于iOS Swift讀取本地json文件報(bào)錯(cuò)的解決方法,需要的朋友可以參考借鑒,下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11
如何利用SwiftUI實(shí)現(xiàn)可縮放的圖片預(yù)覽器
這篇文章主要給大家介紹了關(guān)于如何利用SwiftUI實(shí)現(xiàn)可縮放圖片預(yù)覽器的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用SwiftUI具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-09-09

