defer, Swift'de mevcut kapsamdan çıkıldığında bir kod bloğunun yürütülmesini planlayan bir kontrol akışı yapısıdır. defer bloğu, kapsamın nasıl sonlandığından bağımsız olarak yürütülür — return, break, throw, fatalError veya normal tamamlama. Swift Language Guide'a (2025) göre, aynı kapsamda birden çok defer bulunduğunda, bildirim sırasının tersine yürütülürler — en son bildirilen defer ilk çalışır (LIFO). Bu, defer'i kaynakların garanti edilmiş temizliği için vazgeçilmez kılar: dosya tanımlayıcılarını kapatma, kilitleri serbest bırakma, geçici işaretçileri erken çıkışta temizliği kaçırma riski olmadan serbest bırakma.
Önemli Noktalar
defer, Swift 2.0'da (2015) tanıtılan, bloğunun yürütülmesini mevcut kapsam sona erene kadar erteleyen bir Swift kontrol akışı yapısıdır. Ana özellik: defer, kapsamın nasıl sonlandığından bağımsız olarak gövdesinin yürütüleceğini garanti eder — başarılı (return), hatalı (throw), erken (break, continue) veya ölümcül (fatalError, precondition).
Sözdizimsel olarak defer, defer { /* kod */ } şeklinde yazılır ve kapsam içinde herhangi bir yere yerleştirilebilir. Swift derleyicisi, defer bildirimi ile kapsam sonu arasında bir istisna veya return olsa bile defer içindeki kodun yürütüleceğini garanti eder. Bu, defer'i bir fonksiyonun sonuna yerleştirilen ve erken çıkışta atlanabilen normal koddan temel olarak ayırır.
Chris Lattner'ın (Swift Yaratıcısı, 2015) bir makalesine göre defer, diğer dillerdeki benzer yapılardan ilham almıştır — Go'da defer, Java/Python'da finally, C++'da scope guard — ancak önemli bir farkla: Swift'te defer, kapsamın sonunda yürütülür, bir try-catch bloğundan hemen sonra değil. Bu, birden çok çıkış noktası olan fonksiyonlarda temizlik için daha öngörülebilir bir davranış sağlar.
Simetrik kaynak yönetimi için defer kullanın: dosya aç → defer { close }, kilit al → defer { unlock }. Bu desen, hiçbir koşulda kaynak serbest bırakmanın asla atlanmamasını garanti eder.
Aynı kapsamda birden çok defer bildirildiğinde, bildirim sırasının tersine yürütülürler (LIFO — Last In, First Out). Bu, en son bildirilen defer'in ilk, ilk bildirilenin ise son çalıştığı anlamına gelir:
func exampleDeferOrder() {
defer { print("Birinci defer") }
defer { print("İkinci defer") }
defer { print("Üçüncü defer") }
print("Fonksiyon gövdesi")
}
// Çıktı:
// Fonksiyon gövdesi
// Üçüncü defer
// İkinci defer
// Birinci defer
LIFO sırası, iç içe kaynakların doğru yönetimi için önemlidir. A dosyası önce, B dosyası sonra açılırsa, ters sırada serbest bırakılmalıdırlar: önce B, sonra A. Defer ile bu otomatik olarak gerçekleşir — her kaynağı açtıktan hemen sonra bir defer bildirin ve fonksiyondaki çıkış noktası sayısından bağımsız olarak temizlik sırası doğru olacaktır.
Swift by Sundell'e (2024) göre, bu özellik defer'i iç içe kilitler ve işlemler için ideal kılar: kilit al → defer { unlock } → sonrakini al → defer { unlock }. LIFO, kilitlerin alma sırasının tersine serbest bırakılmasını garanti ederek kilitlenmeleri önler.
defer'in ana kullanım alanı kaynakların garanti edilmiş temizliğidir. Dosya sistemiyle çalışmayı düşünelim. FileHandle aracılığıyla bir dosya açmak, açıkça kapatmayı gerektirir — defer, herhangi bir senaryoda close'un çağrılacağını garanti eder:
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() throw veya return'de bile çağrılacak
}
Bir diğer tipik senaryo, yükleme bayrağı ile UI animasyonlarıdır. Bir yükleme başlatmadan önce, bayrağı isLoading = true olarak ayarlayın ve defer, isteğin başarısı veya başarısızlığından bağımsız olarak fonksiyon çıkışında bayrağı false yapar. Bu, işlenmemiş bir hata nedeniyle bayrağın true kalmasını ve arayüzü sonsuza kadar bloke etmesini önler.
Bitbucket Engineering Blog'a (2024) göre defer, profil oluşturma için de kullanılır: fonksiyonun başında zamanı kaydedin ve defer'de farkı hesaplayıp çıktı olarak verin. Bu, hatalı olanlar dahil tüm yürütme yolları için doğru performans ölçümleri sağlar.
defer, throws fonksiyonlarıyla etkili bir şekilde çalışır. Bir fonksiyon herhangi bir aşamada hata fırlatabildiğinde, defer her catch bloğunda veya guard erken çıkışında kodu tekrarlamadan temizliği garanti eder:
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) ve logAudit(user) çağrılacak
// herhangi bir throw veya return'de
}
Önemli: defer, kontrol catch bloğunun dışına aktarılmadan önce yürütülür, ancak hata oluştuktan sonra. defer içinde bir hata fırlatılırsa, Swift defer içinde doğrudan try kullanımına izin vermez — try? veya try! gerekir. Apple Dokümantasyonuna göre Swift, bir hatanın defer'den kaçmasına izin vermez, çünkü bu bloğun yürütülme garantisini ihlal eder.
Kaynak alımından hemen sonra defer yerleştirin. Bu, yakınlık ilkesini izler: okuyucu alma ve serbest bırakmayı yan yana görür, bu da kod güvenilirliğini artırır ve kod incelemesini basitleştirir.
defer, bildirildiği kapsamdan çıkıldığında yürütülür. defer bir do bloğu içinde bildirilmişse, dış fonksiyondan değil, o bloktan çıkıldığında yürütülür. Bir for döngüsü içindeyse — her yinelemede:
func scopeExample() {
print("start")
do {
defer { print("do-bloğu defer") }
print("inside do")
}
// "do-bloğu defer" burada yazdırılır
print("after do")
}
// Çıktı: start, inside do, do-bloğu defer, after do
for i in 1...3 {
defer { print("end iteration \(i)") }
print("iteration \(i)")
}
// Çıktı: iteration 1, end iteration 1, iteration 2, end iteration 2, ...
defer tarafından yakalanan değişkenler, defer bildirimi anında değil, kapsamdan çıkış anında okunur. defer bildirimi ile kapsam sonu arasında bir değişken değişirse, defer en son değeri görecektir. Bu, yakalamanın oluşturma anında sabitlendiği closure'lardan önemli bir farktır. Dikkatli olun: defer bildirildikten sonra bir değişkende yapılan değişiklikler, yürütülmesini etkileyecektir.
İlk hata — LIFO dışında bir yürütme sırası varsaymak. Temizlik sırası önemliyse ve defer'ler yanlış sırada bildirilirse, kaynaklar bağımlılık ihlalleriyle serbest bırakılabilir. Çözüm: her kaynağı yakaladıktan hemen sonra defer bildirin. İkinci kaynak açıldı → defer { close second }, ilki kapatılmadan önce.
İkinci hata — temizlikle ilgisi olmayan mantık için defer kullanmak. defer, garanti edilmiş temizlik içindir, ana akış kontrolü için değil. defer içindeki kod dönüş değerini etkiliyorsa, bu neredeyse her zaman bir hatadır. defer, bir fonksiyonun dönüş değerini değiştiremez (Java finally'den farklı olarak, finally'deki return orijinal return'ü geçersiz kılar).
Üçüncü hata — defer'den hata fırlatmak. Swift, hata dışarıya yayılabiliyorsa defer içinde try kullanımını yasaklar. Hata fırlatabilecek işlemler için try? veya try! kullanın veya bunları throws içermeyen ayrı bir fonksiyona sarın. O’Reilly “Swift in Depth” (2025)'e göre, iyi bir uygulama temizlik fonksiyonlarını fırlatmasız (non-throwing) yapmak veya hataları defer içinde işlemektir.
Sıkça Sorulan Sorular
defer, mevcut kapsam sona erene kadar bir bloğun yürütülmesini erteleyen bir Swift yapısıdır. Blok her zaman yürütülür — return, throw, break veya normal tamamlamada. Kaynakların garanti edilmiş temizliği için kullanılır: dosyaları kapatma, kilitleri serbest bırakma.
Bildirim sırasının tersine (LIFO) — en son bildirilen defer ilk çalışır. Bu, iç içe kaynakların doğru temizliğini garanti eder: B kaynağı A'dan sonra açılırsa, A'dan önce kapatılır ve zaten serbest bırakılmış kaynaklara bağımlılığı önler.
Doğrudan değil — Swift, defer'den hata yayılmasını engeller. Hata fırlatabilecek işlemler için try? veya try! kullanın. En iyi uygulama, temizlik fonksiyonlarını fırlatmasız yapmak veya hataları defer içinde dışarıya yaymadan işlemektir.
defer bir kapsama bağlıdır ve return, throw ve break dahil herhangi bir çıkışta yürütülür. finally (diğer dillerde) try-catch'e bağlıdır ve yalnızca try varsa yürütülür. Swift'te finally yoktur — defer bu senaryoyu tamamen kapsar ve yalnızca hata işleme için değil, herhangi bir kapsam için çalışır.
Evet, defer, bildirim anında değil, kapsamdan çıkış anında değişkenleri okur. defer bildirildikten sonra bir değişken değişirse, defer bloğu en son değeri görecektir. Bu, yakalamanın oluşturma anında sabitlendiği normal closure'lardan farklıdır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun