defer — isang control construct sa Swift na nag-iskedyul ng execution ng isang code block sa sandali ng paglabas mula sa kasalukuyang scope. Ang defer block ay isinasagawa anuman ang paraan ng pagtatapos — return, break, throw, fatalError o normal na pagtatapos. Ayon sa Swift Language Guide (2025), kapag may maraming defer sa isang scope, ang mga ito ay isinasagawa sa reverse order ng deklarasyon — ang huling na-deklara ay unang isinasagawa (LIFO). Ginagawa nitong kailangang-kailangan ang defer para sa garantisadong paglilinis ng resources: pagsasara ng file descriptors, pag-aalis ng mga lock, pagpapalaya ng temporary pointers nang walang panganib na makaligtaan ang cleanup sa maagang paglabas.
Mga Pangunahing
defer — ay isang control construct ng wikang Swift, ipinakilala sa Swift 2.0 (2015), na nagpapaantala sa execution ng block nito hanggang sa sandaling matapos ang kasalukuyang scope. Pangunahing tampok: ginagarantiya ng defer ang execution ng body nito anuman ang eksaktong paraan ng pagtatapos ng scope — matagumpay (return), may error (throw), maaga (break, continue) o fatal (fatalError, precondition).
Sa syntax, ang defer ay mukhang defer { /* code */ } at maaaring ilagay kahit saan sa loob ng scope. Ginagarantiya ng Swift compiler na ang code sa loob ng defer ay isasagawa, kahit na sa pagitan ng deklarasyon ng defer at ng pagtatapos ng scope ay may exception o return. Ito ang pangunahing pinagkaiba ng defer sa ordinaryong code na inilalagay sa dulo ng function, na maaaring laktawan sa maagang paglabas.
Ayon sa artikulo ni Chris Lattner (Tagalikha ng Swift, 2015), ang defer ay inspirasyon ng mga katulad na construct sa ibang mga wika — defer sa Go, finally sa Java/Python, scope guard sa C++ — ngunit may mahalagang pagkakaiba: sa Swift, ang defer ay isinasagawa sa dulo ng scope, hindi kaagad pagkatapos ng try-catch block. Ito ay nagbibigay ng mas predictable na pag-uugali para sa cleanup sa mga function na may maraming exit point.
Gamitin ang defer para sa simetriko na pamamahala ng resources: pagbubukas ng file → defer { close }, pagtatakda ng lock → defer { unlock }. Ginagarantiya ng ganitong pattern na ang pagpapalaya ng resource ay hindi makaligtaan sa anumang sitwasyon.
Kapag maraming defer ang na-deklara sa isang scope, ang mga ito ay isinasagawa sa reverse order ng deklarasyon (LIFO — Last In, First Out). Ibig sabihin, ang huling na-deklarang defer ay unang isasagawa, at ang una — huli:
func exampleDeferOrder() {
defer { print("Unang defer") }
defer { print("Pangalawang defer") }
defer { print("Pangatlong defer") }
print("Body ng function")
}
// Output:
// Body ng function
// Pangatlong defer
// Pangalawang defer
// Unang defer
Mahalaga ang LIFO order para sa tamang pamamahala ng nested resources. Kung unang bubuksan ang file A, pagkatapos ay file B, kailangan silang palayain sa reverse order: una B, pagkatapos A. Sa defer, ito ay awtomatikong nangyayari — ideklara ang defer kaagad pagkatapos buksan ang bawat resource, at ang order ng paglilinis ay tama anuman ang bilang ng exit point mula sa function.
Ayon sa Swift by Sundell (2024), ang feature na ito ay ginagawang perpekto ang defer para sa nested locks at transaksyon: pagkuha ng lock → defer { unlock } → pagkuha ng susunod → defer { unlock }. Ginagarantiya ng LIFO na ang mga lock ay pinapalaya sa reverse order ng pagkuha, na pumipigil sa deadlock.
Pangunahing gamit ng defer — garantisadong paglilinis ng resources. Isaalang-alang ang pagtatrabaho sa file system. Ang pagbubukas ng file sa pamamagitan ng FileHandle ay nangangailangan ng eksplicitong pagsasara — ginagarantiya ng defer na ang close ay tatawagin sa anumang senaryo:
func readFile(path: String) throws -> String {
let handle = try FileHandle(forReadingFrom: URL(fileURLWithPath: path))
defer { try? handle.close() }
let data = try handle.readToEnd()
guard let data else { throw FileError.empty() }
return String(data: data, encoding: .utf8) ?? ""
// Ang handle.close() ay tatawagin kahit sa throw o return
}
Isa pang karaniwang senaryo — UI-animation na may loading flag. Bago magsimula ang pag-load, ang flag na isLoading = true ay itinatakda, at ang defer ay nagpapalit nito sa false sa paglabas mula sa function, anuman ang tagumpay o error ng request. Pinipigilan nito ang sitwasyon kung saan ang flag ay nananatiling true dahil sa hindi naprosesong error at hinaharangan ang interface magpakailanman.
Ayon sa Bitbucket Engineering Blog (2024), ang defer ay ginagamit din para sa profiling: sa simula ng function ay maaaring itala ang oras, at sa defer — kalkulahin at ipakita ang pagkakaiba. Ito ay nagbibigay ng tumpak na pagsukat ng performance ng lahat ng execution path, kasama ang mga may error.
defer ay epektibong pinagsama sa throws-function. Kapag ang isang function ay maaaring mag-throw ng error sa anumang yugto, ginagarantiya ng defer ang cleanup nang hindi dudublikahin ang code sa bawat catch block o guard early exit:
func processTransaction() throws {
let db = try openDatabase()
defer { closeDatabase(db) }
let user = try fetchUser(from: db)
defer { logAudit(user) }
let result = try performPayment(user)
sendNotification(result)
// Ang closeDatabase(db) at logAudit(user) ay tatawagin
// sa bawat throw o return
}
Mahalaga: ang defer ay isinasagawa bago ang paglipat ng kontrol mula sa catch block, ngunit pagkatapos ng paglitaw ng error. Kung ang error ay na-throw sa defer, hindi pinapayagan ng Swift ang direktang paggamit ng try sa loob ng defer — kinakailangan ang try? o try!. Ayon sa Apple Documentation, hindi pinapayagan ng Swift na ang error ay „makatakas" mula sa defer, dahil lalabag ito sa garantiya ng execution ng block.
Ilagay ang defer kaagad pagkatapos makuha ang resource. Ito ay sumusunod sa prinsipyo ng proximity: nakikita ng mambabasa ang pagkuha at pagpapalaya na magkatabi, na nagpapataas ng reliability ng code at nagpapasimple ng code review.
defer ay isinasagawa sa paglabas mula sa scope kung saan ito na-deklara. Kung ang defer ay na-deklara sa loob ng do-block, ito ay isinasagawa sa paglabas mula sa block na ito, hindi mula sa panlabas na function. Kung nasa loob ng for-loop — sa bawat iteration:
func scopeExample() {
print("start")
do {
defer { print("defer sa do-block") }
print("inside do")
}
// "defer sa do-block" ay nag-print dito
print("after do")
}
// Output: start, inside do, defer sa do-block, after do
for i in 1...3 {
defer { print("end iteration \(i)") }
print("iteration \(i)")
}
// Output: iteration 1, dulo ng iteration 1, iteration 2, dulo ng iteration 2, ...
Ang mga variable na na-capture ng defer ay binabasa sa sandali ng paglabas mula sa scope, hindi sa sandali ng deklarasyon ng defer. Kung ang variable ay nagbabago sa pagitan ng deklarasyon ng defer at ng pagtatapos ng scope, makikita ng defer ang huling halaga. Ito ay mahalagang pagkakaiba mula sa closures, kung saan ang pag-capture ay nangyayari sa sandali ng paggawa. Mag-ingat: ang mga pagbabago ng variable pagkatapos ng deklarasyon ng defer ay makakaapekto sa execution nito.
Unang pagkakamali — pagpapalagay tungkol sa order ng execution na iba sa LIFO. Kung mahalaga ang order ng cleanup at ang mga defer ay na-deklara sa maling order, ang resources ay maaaring palayain na may paglabag sa dependencies. Solusyon: ideklara ang defer kaagad pagkatapos makuha ang bawat resource. Pangalawang resource na binuksan → defer { close second } bago isara ang una.
Pangalawang pagkakamali — paggamit ng defer para sa logic na hindi nauugnay sa paglilinis. Ang defer ay dinisenyo para sa garantisadong cleanup, hindi para sa pangunahing control flow. Kung ang code sa defer ay nakakaapekto sa ibinalik na halaga, ito ay halos palaging pagkakamali. Hindi maaaring baguhin ng defer ang return value ng function (hindi tulad ng Java finally, kung saan ang return sa finally ay nag-o-override sa orihinal na return).
Pangatlong pagkakamali — pag-throw ng error mula sa defer. Ipinagbabawal ng Swift ang try sa loob ng defer kung ang error ay maaaring kumalat sa labas. Gamitin ang try? o try! para sa mga operasyon na maaaring mag-throw ng error, o balutin ang mga ito sa isang hiwalay na function na walang throws. Ayon sa O'Reilly „Swift in Depth" (2025), magandang praktika na gawing non-throwing ang cleanup functions o hawakan ang mga error sa loob ng defer.
Mga Madalas Itanong
defer — isang Swift control construct na nagpapaantala sa execution ng block hanggang sa paglabas mula sa kasalukuyang scope. Ang block ay palaging isinasagawa — sa return, throw, break o normal na pagtatapos. Ginagamit para sa garantisadong paglilinis ng resources: pagsasara ng mga file, pag-aalis ng mga lock.
Sa reverse order ng deklarasyon (LIFO) — ang huling na-deklarang defer ay unang isinasagawa. Ito ay ginagarantiya ang tamang cleanup ng nested resources: kung ang resource B ay binuksan pagkatapos ng A, ito ay isasara bago ang A, na pumipigil sa dependencies sa mga nai-release nang resources.
Hindi direkta — ipinagbabawal ng Swift ang pagkalat ng error mula sa defer. Gamitin ang try? o try! para sa mga operasyon na maaaring mag-throw ng error. Ang pinakamahusay na praktika ay gawing non-throwing ang cleanup functions o hawakan ang mga error sa loob ng defer nang hindi ikinakalat sa labas.
defer ay nakatali sa scope at isinasagawa sa bawat paglabas, kasama ang return, throw at break. Ang finally (sa ibang wika) ay nakatali sa try-catch at isinasagawa lamang sa pagkakaroon ng try. Sa Swift ay walang finally — ganap na sinasaklaw ng defer ang senaryong ito at gumagana para sa anumang scope, hindi lamang para sa paghawak ng error.
Oo, binabasa ng defer ang mga variable sa sandali ng paglabas mula sa scope, hindi sa sandali ng deklarasyon. Kung ang variable ay nagbabago pagkatapos ng deklarasyon ng defer, makikita ng defer block ang huling halaga. Ito ay naiiba mula sa ordinaryong closures, kung saan ang pag-capture ay naayos sa sandali ng paggawa.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din