defer — bu nədir, sintaksis və icra ardıcıllığı

Müəllif: IT Sectr Dərc olunub: 2026-06-20 Oxuma vaxtı: 8 dəq

defer — Swift-də kod blokunun icrasını cari görünmə sahəsindən (scope) çıxış anına planlaşdıran idarəetmə konstruksiyası. defer bloku bitmə üsulundan asılı olmayaraq icra olunur — return, break, throw, fatalError və ya normal bitmə. Swift Language Guide (2025) məlumatına görə, bir scope-da bir neçə defer olduqda onlar tərs elan olunma ardıcıllığı ilə icra olunur — sonuncu elan olunan birinci icra olunur (LIFO). Bu, defer-i resursların təminatlı təmizlənməsi üçün əvəzolunmaz edir: fayl deskriptorlarının bağlanması, blokların götürülməsi, müvəqqəti göstəricilərin azad edilməsi vaxtından əvvəl çıxışda cleanup-ı qaçırma riski olmadan.

Əsas

  • defer — görünmə sahəsindən çıxışda, çıxış səbəbindən asılı olmayaraq icra olunan kod bloku (return, throw, break)
  • Ardıcıllıq LIFO: bir neçə defer aşağıdan yuxarı icra olunur — sonuncu elan olunan birinci işə düşür
  • Resurs təmizlənməsi — əsas tətbiq: faylların bağlanması, blokların götürülməsi, animasiyaların bitirilməsi
  • Dəyişənlərin təyini: defer dəyişənləri çıxış anında görür, elan anında deyil
  • Əvəz etmir do-catch-i xəta idarəetməsi üçün — defer cleanup-a cavabdehdir, axın nəzarətinə deyil

Defer nədir?

defer — Swift 2.0-da (2015) təqdim edilmiş, blokunun icrasını cari scope-un bitmə anına qədər təxirə salan idarəetmə konstruksiyasıdır. Əsas xüsusiyyət: defer scope-un necə bitməsindən asılı olmayaraq bədəninin icrasını təmin edir — uğurlu (return), xəta ilə (throw), vaxtından əvvəl (break, continue) və ya fatal (fatalError, precondition).

Sintaktik olaraq defer defer { /* kod */ } kimi görünür və scope daxilində istənilən yerdə yerləşə bilər. Swift kompilyatoru defer daxilindəki kodun, hətta defer-in elanı ilə scope-un sonu arasında istisna və ya return baş versə belə, icra olunacağına zəmanət verir. Bu, defer-i funksiyanın sonunda yerləşdirilən və vaxtından əvvəl çıxışda buraxıla bilən adi koddan prinsipial olaraq fərqləndirir.

Chris Lattner-in (Swift Yaradıcısı, 2015) məqaləsinə görə, defer digər dillərdəki analoji konstruksiyalardan ilhamlanıb — defer Go-da, finally Java/Python-da, scope guard C++-da — lakin vacib fərqlə: Swift-də defer scope-un sonunda icra olunur, try-catch blokundan dərhal sonra deyil. Bu, çoxsaylı çıxış nöqtələri olan funksiyalarda cleanup üçün daha proqnozlaşdırıla bilən davranış verir.

Resursların simmetrik idarə edilməsi üçün defer-dən istifadə edin: faylın açılması → defer { close }, blokun qoyulması → defer { unlock }. Belə nümunə resursun azad edilməsinin heç bir şəraitdə buraxılmamasını təmin edir.

Bir neçə defer-in icra ardıcıllığı

Bir scope-da bir neçə defer elan edildikdə, onlar elan olunmanın tərs ardıcıllığı ilə icra olunur (LIFO — Last In, First Out). Bu o deməkdir ki, sonuncu elan olunan defer birinci icra olunacaq, birinci isə sonuncu:

swift
func exampleDeferOrder() {
    defer { print("Birinci defer") }
    defer { print("İkinci defer") }
    defer { print("Üçüncü defer") }

    print("Funksiya gövdəsi")
}
// Nəticə:
// Funksiya gövdəsi
// Üçüncü defer
// İkinci defer
// Birinci defer

LIFO ardıcıllığı iç-içə resursların düzgün idarə edilməsi üçün vacibdir. Əvvəlcə A faylı, sonra B faylı açılırsa, onları tərs ardıcıllıqla azad etmək lazımdır: əvvəlcə B, sonra A. Defer ilə bu avtomatik baş verir — hər resursun açılmasından dərhal sonra defer elan edin və təmizlənmə ardıcıllığı funksiyadan çıxış nöqtələrinin sayından asılı olmayaraq düzgün olacaq.

Swift by Sundell (2024) məlumatına görə, bu xüsusiyyət defer-i iç-içə bloklar və tranzaksiyalar üçün ideal edir: blokun ələ keçirilməsi → defer { unlock } → növbətinin ələ keçirilməsi → defer { unlock }. LIFO blokların ələ keçirilmənin tərs ardıcıllığı ilə azad olunmasını təmin edir, qarşılıqlı bloklanmanın qarşısını alır.

Defer resursların təmizlənməsi üçün

Defer-in əsas tətbiqi — resursların təminatlı təmizlənməsi. Fayl sistemi ilə işi nəzərdən keçirək. Faylın FileHandle vasitəsilə açılması aşkar bağlanma tələb edir — defer istənilən ssenaridə close-un çağırılacağına zəmanət verir:

swift
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() hətta throw və ya return zamanı belə çağırılacaq
}

Digər tipik ssenari — yükləmə bayrağı ilə UI-animasiyalar. Yükləmə başlamazdan əvvəl isLoading = true bayrağı qoyulur, defer isə funksiyadan çıxışda sorğunun uğurundan və ya xətasından asılı olmayaraq onu false edir. Bu, bayrağın işlənməmiş xəta səbəbindən true qalmasının və interfeysi əbədi bloklamasının qarşısını alır.

Bitbucket Engineering Blog (2024) məlumatına görə, defer profil üçün də istifadə olunur: funksiyanın əvvəlində vaxt qeydə alına, defer-də isə fərq hesablanıb çıxarıla bilər. Bu, səhv olanlar da daxil olmaqla bütün icra yollarının dəqiq performans ölçülərini verir.

Defer və xəta idarəetməsi

defer throws-funksiyaları ilə effektiv birləşir. Funksiya istənilən mərhələdə xəta atmaq imkanına malik olduqda, defer hər catch blokunda və ya guard-ın erkən çıxışında kodun təkrarlanması olmadan cleanup-ı təmin edir:

swift
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) və logAudit(user) hər throw və ya return zamanı çağırılacaq
    // hər throw və ya return zamanı
}

Vacib: defer catch blokundan idarəetmənin ötürülməsindən əvvəl, lakin xətanın baş verməsindən sonra icra olunur. Əgər defer-də xəta atılıbsa, Swift birbaşa defer daxilində try istifadəsinə icazə vermir — try? və ya try! tələb olunur. Apple Documentation-a görə, Swift xətanın defer-dən „çıxmasına" icazə vermir, çünki bu blokun icra zəmanətini pozardı.

Defer-i resursun ələ keçirilməsindən dərhal sonra yerləşdirin. Bu yaxınlıq prinsipinə əməl edir: oxucu ələ keçirmə və azad etməni yan-yana görür, bu kodun etibarlılığını artırır və kod nəzərdən keçirməsini sadələşdirir.

Görünmə sahəsi qaydaları

defer elan olunduğu scope-dan çıxışda icra olunur. Əgər defer do-bloku daxilində elan olunubsa, o, xarici funksiyadan deyil, bu blokdan çıxışda icra olunur. Əgər for-dövriyyəsi daxilindədirsə — hər iterasiyada:

swift
func scopeExample() {
    print("start")
    do {
        defer { print("do-blok defer") }
        print("inside do")
    }
    // "do-blok defer" burada çap edir
    print("after do")
}
    // Nəticə: start, inside do, do-blok defer, after do

for i in 1...3 {
    defer { print("end iteration \(i)") }
    print("iteration \(i)")
}
    // Nəticə: iterasiya 1, iterasiyanın sonu 1, iterasiya 2, iterasiyanın sonu 2, ...

Defer tərəfindən ələ keçirilən dəyişənlər scope-dan çıxış anında oxunur, defer-in elan anında deyil. Əgər dəyişən defer-in elanı ilə scope-un sonu arasında dəyişirsə, defer son dəyəri görəcək. Bu, ələ keçirmənin yaradılma anında baş verdiyi bağlanmalardan vacib fərqdir. Diqqətli olun: defer-in elanından sonra dəyişənin dəyişməsi onun icrasına təsir edəcək.

Defer ilə tipik səhvlər

Birinci səhv — LIFO-dan fərqli icra ardıcıllığı fərziyyəsi. Cleanup ardıcıllığı vacibdirsə və defer-lər səhv ardıcıllıqla elan olunubsa, resurslar asılılıq pozuntusu ilə azad edilə bilər. Həll yolu: hər resursun ələ keçirilməsindən dərhal sonra defer elan edin. İkinci resurs açıldı → defer { close second } birinci bağlanmazdan əvvəl.

İkinci səhv — təmizlənmə ilə əlaqəsi olmayan məntiq üçün defer istifadəsi. defer təminatlı cleanup üçün nəzərdə tutulub, əsas idarəetmə axını üçün deyil. Əgər defer-dəki kod qaytarılan dəyərə təsir edirsə, bu demək olar ki, həmişə səhvdir. defer funksiyanın return dəyərini dəyişə bilməz (Java finally-dən fərqli olaraq, burada finally-də return orijinal return-ı ləğv edir).

Üçüncü səhv — defer-dən xəta atmaq. Swift defer daxilində try-yə qadağa qoyur, əgər xəta kənara yayıla bilərsə. Xəta ata bilən əməliyyatlar üçün try? və ya try! istifadə edin və ya onları throws olmadan ayrıca funksiyaya sarın. O'Reilly „Swift in Depth" (2025) görə, yaxşı təcrübə cleanup funksiyalarını atmayan (non-throwing) etmək və ya xətaları defer daxilində idarə etməkdir.

Tez-tez verilən suallar

Swift-də defer nədir?

defer — blokun icrasını cari görünmə sahəsindən çıxışa qədər təxirə salan Swift idarəetmə konstruksiyası. Blok həmişə icra olunur — return, throw, break və ya normal bitmədə. Resursların təminatlı təmizlənməsi üçün istifadə olunur: faylların bağlanması, blokların götürülməsi.

Bir neçə defer hansı ardıcıllıqla icra olunur?

Elan olunmanın tərs ardıcıllığı ilə (LIFO) — sonuncu elan olunan defer birinci icra olunur. Bu, iç-içə resursların düzgün cleanup-ını təmin edir: əgər B resursu A-dan sonra açılıbsa, A-dan əvvəl bağlanacaq, bu da artıq azad edilmiş resurslardan asılılığın qarşısını alır.

Defer-dən xəta atmaq olarmı?

Birbaşa yox — Swift defer-dən xətanın yayılmasını qadağan edir. Xəta ata bilən əməliyyatlar üçün try? və ya try! istifadə edin. Ən yaxşı təcrübə cleanup funksiyalarını non-throwing etmək və ya xətaları defer daxilində kənara atmadan idarə etməkdir.

Defer və do-catch-finally arasında nə fərq var?

defer scope-a bağlıdır və istənilən çıxışda icra olunur, o cümlədən return, throw və break. finally (digər dillərdə) try-catch-ə bağlıdır və yalnız try olduqda icra olunur. Swift-də finally yoxdur — defer bu ssenarini tamamilə əhatə edir və yalnız xəta idarəetməsi üçün deyil, istənilən scope üçün işləyir.

Defer öz elanından sonra dəyişənlərin dəyişməsini görürmü?

Bəli, defer dəyişənləri scope-dan çıxış anında oxuyur, elan anında deyil. Əgər dəyişən defer-in elanından sonra dəyişirsə, defer bloku son dəyəri görəcək. Bu, ələ keçirmənin yaradılma anında sabitləndiyi adi bağlanmalardan fərqlənir.

Nəticə

  • defer — səbəbdən asılı olmayaraq scope-dan çıxışda icra olunan finalizasiya bloku (return, throw, break, normal bitmə)
  • LIFO ardıcıllığı — bir neçə defer aşağıdan yuxarı icra olunur, sonuncu elan olunan — birinci icra olunan
  • Resursların təmizlənməsi — əsas tətbiq: faylların bağlanması, blokların götürülməsi, göstəricilərin azad edilməsi, animasiyaların dayandırılması
  • Uyğunluq throws ilə: defer xətadan sonra, lakin catch blokundan çıxışdan əvvəl icra olunur; defer-dən xəta yayılmır
  • Scope: defer elan olunduğu scope-dan çıxışda icra olunur — do-bloku, dövriyyə, funksiya
  • Dəyişənlərin ələ keçirilməsi: defer dəyərləri çıxış anında oxuyur, elan anında deyil — mutasiyalara diqqətli olun
  • Ən yaxşı təcrübə: defer-i resursun ələ keçirilməsindən dərhal sonra elan edin, defer-i biznes məntiqi üçün istifadə etməyin, cleanup funksiyalarını non-throwing edin

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun