defer — Swiftda kod blokining bajarilishini joriy ko'rinish sohasidan (scope) chiqish momentiga rejalashtiruvchi boshqaruv konstruksiyasi. defer bloki tugash usulidan qat'i nazar bajariladi — return, break, throw, fatalError yoki normal tugash. Swift Language Guide (2025) ma'lumotlariga ko'ra, bir scope-da bir nechta defer mavjud bo'lganda ular e'lon qilishning teskari tartibida bajariladi — oxirgi e'lon qilingan birinchi bajariladi (LIFO). Bu deferni resurslarning kafolatlangan tozalanishi uchun ajralmas qiladi: fayl deskriptorlarini yopish, blokirovkalarni olish, vaqtinchalik ko'rsatkichlarni bo'shatish muddatidan oldin chiqishda cleanup-ni o'tkazib yuborish xavfisiz.
Asosiy
defer — Swift 2.0 (2015) da joriy qilingan, blokining bajarilishini joriy scope tugash momentigacha kechiktiradigan boshqaruv konstruksiyasi. Asosiy xususiyat: defer scope qanday tugashidan qat'i nazar o'z tanasining bajarilishini kafolatlaydi — muvaffaqiyatli (return), xato bilan (throw), muddatidan oldin (break, continue) yoki fatal (fatalError, precondition).
Sintaktik jihatdan defer defer { /* kod */ } ko'rinishiga ega va scope ichida istalgan joyda joylashishi mumkin. Swift kompilyatori defer ichidagi kodning, hatto defer e'lon qilinishi bilan scope oxiri o'rtasida istisno yoki return yuz bersa ham, bajarilishini kafolatlaydi. Bu deferni funksiya oxirida joylashtirilgan va muddatidan oldin chiqishda o'tkazib yuborilishi mumkin bo'lgan oddiy koddan tubdan farqlaydi.
Chris Lattner (Swift Yaratuvchisi, 2015) maqolasiga ko'ra, defer boshqa tillardagi o'xshash konstruksiyalardan ilhomlangan — defer Go-da, finally Java/Python-da, scope guard C++-da — lekin muhim farq bilan: Swiftda defer scope oxirida bajariladi, try-catch blokidan darhol keyin emas. Bu ko'p chiqish nuqtalari bo'lgan funksiyalarda cleanup uchun oldindan aytish mumkin bo'lgan xatti-harakatni ta'minlaydi.
Resurslarni simmetrik boshqarish uchun deferdan foydalaning: faylni ochish → defer { close }, blokirovkani o'rnatish → defer { unlock }. Bunday namuna resursning bo'shatilishi hech qanday sharoitda o'tkazib yuborilmasligini kafolatlaydi.
Bir scope-da bir nechta defer e'lon qilinganda, ular e'lon qilishning teskari tartibida bajariladi (LIFO — Last In, First Out). Bu oxirgi e'lon qilingan defer birinchi bajariladi, birinchi esa oxirgi degani:
func exampleDeferOrder() {
defer { print("Birinchi defer") }
defer { print("Ikkinchi defer") }
defer { print("Uchinchi defer") }
print("Funksiya tanasi")
}
// Natija:
// Funksiya tanasi
// Uchinchi defer
// Ikkinchi defer
// Birinchi defer
LIFO tartibi ichma-ich resurslarni to'g'ri boshqarish uchun muhim. Avval A fayli, keyin B fayli ochilsa, ularni teskari tartibda bo'shatish kerak: avval B, keyin A. Defer bilan bu avtomatik sodir bo'ladi — har bir resursni ochgandan so'ng darhol defer e'lon qiling va tozalash tartibi funksiyadan chiqish nuqtalari sonidan qat'i nazar to'g'ri bo'ladi.
Swift by Sundell (2024) ma'lumotlariga ko'ra, bu xususiyat deferni ichma-ich blokirovkalar va tranzaksiyalar uchun ideal qiladi: blokirovkani olish → defer { unlock } → keyingisini olish → defer { unlock }. LIFO blokirovkalarning olishning teskari tartibida bo'shatilishini kafolatlaydi, tiqilishlarning oldini oladi.
Deferning asosiy qo'llanishi — resurslarning kafolatlangan tozalanishi. Fayl tizimi bilan ishlashni ko'rib chiqamiz. Faylni FileHandle orqali ochish aniq yopishni talab qiladi — defer har qanday stsenariyda close chaqirilishini kafolatlaydi:
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) ?? ""
// handle.close() hatto throw yoki return da ham chaqiriladi
}
Yana bir odatiy stsenariy — yuklash bayrog'i bilan UI-animatsiyalar. Yuklash boshlanishidan oldin isLoading = true bayrog'i o'rnatiladi, defer esa funksiyadan chiqishda so'rovning muvaffaqiyati yoki xatosidan qat'i nazar uni false ga o'zgartiradi. Bu bayroqning ishlanmagan xato tufayli true bo'lib qolishi va interfeysni abadiy bloklashining oldini oladi.
Bitbucket Engineering Blog (2024) ma'lumotlariga ko'ra, defer profiling uchun ham qo'llaniladi: funksiya boshida vaqtni yozib olish, deferda esa farqni hisoblash va chiqarish mumkin. Bu xato yo'llari ham kiradi, barcha bajarilish yo'llarining aniq performans o'lchovlarini beradi.
defer throws-funksiyalari bilan samarali birlashadi. Funksiya istalgan bosqichda xato tashlashi mumkin bo'lganda, defer har bir catch blokida yoki guardning erta chiqishida kodni takrorlamasdan cleanup-ni kafolatlaydi:
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)
// closeDatabase(db) va logAudit(user) har bir throw yoki return da chaqiriladi
// har bir throw yoki return da
}
Muhim: defer catch blokidan boshqaruvni uzatishdan oldin, lekin xato yuz berishidan keyin bajariladi. Agar deferda xato tashlangan bo'lsa, Swift defer ichida to'g'ridan-to'g'ri try ishlatishga ruxsat bermaydi — try? yoki try! talab qilinadi. Apple Documentation ga ko'ra, Swift xatoning deferdan „chiqib ketishiga" ruxsat bermaydi, chunki bu blokning bajarilish kafolatini buzardi.
Deferni resursni olishdan so'ng darhol joylashtiring. Bu yaqinlik printsipiga amal qiladi: o'quvchi olish va bo'shatishni yonma-yon ko'radi, bu kodning ishonchliligini oshiradi va kodni ko'rib chiqishni soddalashtiradi.
defer e'lon qilingan scope-dan chiqishda bajariladi. Agar defer do-bloki ichida e'lon qilingan bo'lsa, u tashqi funksiyadan emas, bu blokdan chiqishda bajariladi. Agar for-sikli ichida bo'lsa — har bir iteratsiyada:
func scopeExample() {
print("start")
do {
defer { print("do-blok defer") }
print("inside do")
}
// "do-blok defer" bu yerda chop etadi
print("after do")
}
// Natija: start, inside do, do-blok defer, after do
for i in 1...3 {
defer { print("end iteration \(i)") }
print("iteration \(i)")
}
// Natija: iteratsiya 1, iteratsiya oxiri 1, iteratsiya 2, iteratsiya oxiri 2, ...
Defer tomonidan olingan o'zgaruvchilar scope-dan chiqish momentida o'qiladi, defer e'lon qilish momentida emas. Agar o'zgaruvchi defer e'lon qilinishi bilan scope oxiri o'rtasida o'zgarsa, defer oxirgi qiymatni ko'radi. Bu olish yaratilish momentida qayd etiladigan yopilmalardan (closures) muhim farqdir. Diqqatli bo'ling: defer e'lon qilinganidan keyin o'zgaruvchining o'zgarishi uning bajarilishiga ta'sir qiladi.
Birinchi xato — LIFO dan farqli bajarilish tartibi haqidagi taxmin. Agar cleanup tartibi muhim bo'lsa va deferlar noto'g'ri tartibda e'lon qilingan bo'lsa, resurslar bog'liqlikni buzgan holda bo'shatilishi mumkin. Yechim: har bir resursni olgandan so'ng darhol defer e'lon qiling. Ikkinchi resurs ochildi → defer { close second } birinchisi yopilishidan oldin.
Ikkinchi xato — tozalash bilan bog'liq bo'lmagan mantiq uchun deferdan foydalanish. defer kafolatlangan cleanup uchun mo'ljallangan, asosiy boshqaruv oqimi uchun emas. Agar deferdagi kod qaytariladigan qiymatga ta'sir qilsa, bu deyarli har doim xato. defer funksiyaning return qiymatini o'zgartira olmaydi (Java finally-dan farqli o'laroq, unda finally-dagi return asl return-ni bekor qiladi).
Uchinchi xato — deferdan xato tashlash. Swift defer ichida try ni taqiqlaydi, agar xato tashqariga tarqalishi mumkin bo'lsa. Xato tashlashi mumkin bo'lgan operatsiyalar uchun try? yoki try! dan foydalaning yoki ularni throws-siz alohida funksiyaga o'rang. O'Reilly „Swift in Depth" (2025) ga ko'ra, yaxshi amaliyot cleanup funksiyalarini non-throwing qilish yoki xatolarni defer ichida boshqarishdir.
Tez-tez beriladigan savollar
defer — blokning bajarilishini joriy ko'rinish sohasidan chiqishgacha kechiktiradigan Swift boshqaruv konstruksiyasi. Blok har doim bajariladi — return, throw, break yoki normal tugashda. Resurslarning kafolatlangan tozalanishi uchun qo'llaniladi: fayllarni yopish, blokirovkalarni olish.
E'lon qilishning teskari tartibida (LIFO) — oxirgi e'lon qilingan defer birinchi bajariladi. Bu ichma-ich resurslarning to'g'ri cleanup-ni kafolatlaydi: agar B resursi A dan keyin ochilgan bo'lsa, A dan oldin yopiladi, bu allaqachon bo'shatilgan resurslarga bog'liqlikning oldini oladi.
To'g'ridan-to'g'ri yo'q — Swift deferdan xatoning tarqalishini taqiqlaydi. Xato tashlashi mumkin bo'lgan operatsiyalar uchun try? yoki try! dan foydalaning. Eng yaxshi amaliyot cleanup funksiyalarini non-throwing qilish yoki xatolarni defer ichida tashqariga tarqatmasdan boshqarishdir.
defer scope-ga bog'langan va har qanday chiqishda bajariladi, jumladan return, throw va break. finally (boshqa tillarda) try-catch-ga bog'langan va faqat try mavjud bo'lganda bajariladi. Swiftda finally yo'q — defer bu stsenariyni to'liq qoplaydi va faqat xatolarni boshqarish uchun emas, istalgan scope uchun ishlaydi.
Ha, defer o'zgaruvchilarni scope-dan chiqish momentida o'qiydi, e'lon qilish momentida emas. Agar o'zgaruvchi defer e'lon qilinganidan keyin o'zgarsa, defer bloki oxirgi qiymatni ko'radi. Bu olish yaratilish momentida qayd etiladigan oddiy yopilmalardan farq qiladi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.