ProgramlamaiOS Geliştirici

Swift'te escaping ve non-escaping closure nedir? Closure'lar ile çalışmanın doğru organizasyonu nasıl olmalı, kullanımlarında hangi ince noktalar var ve bu, asenkron kod ile çalışırken ne gibi sorunlar doğurabilir?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Escaping closure — bir closure'ın çağıran fonksiyonun kapsamından "çıktığı" durum (örneğin, asenkron yürütme için saklanır).

Swift'te fonksiyonlar varsayılan olarak non-escaping closure alır: closure, fonksiyon çağrısı içerisinde yürütülür.

Escaping belirtmek için @escaping anahtar kelimesi kullanılır:

func asyncTask(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }

Ana farklar:

  • Escaping closure’lar saklanabilir ve daha sonra çağrılabilir.
  • Escaping closure içinde self'i yakalamak için — bellek sızıntılarını (retain cycle) önlemek için [weak self] veya [unowned self] belirtilmesi gerekir.

Soru - Tuzak.

DispatchQueue.async fonksiyonuna parametre olarak geçen closure’lar için her zaman @escaping yazmak gerekir mi?

— Evet. Çünkü DispatchQueue.async closure'ı yürütme anına kadar sakladığı için, closure escaping olur.

Örnek:

func foo(action: () -> Void) { DispatchQueue.main.async { action() // Derlenmeyecek: closure escaping olmalı. } } // Gerekli: func bar(action: @escaping () -> Void) { ... }

Konunun inceliklerini bilmemekten kaynaklanan gerçek hata örnekleri.


Hikaye

Kontrolör, escaping closure içinde self'e güçlü bir referans oluşturdu (örneğin, ağ isteği). Kontrolör ekranın dışına çıkar çıkmaz serbest bırakılmadı — güçlü bir retain cycle. Çözüm: [weak self] veya [unowned self] kullanmak.


Hikaye

Fonksiyon closure'ı DispatchQueue.async'e iletti, ancak onu escaping olarak işaretlemedi. Proje derlenmedi, hataları bulmak zor oldu çünkü fonksiyonlar iç içe geçmişti.


Hikaye

Closure içinde, closure'ın çağrıldığı anda zaten de-initialized olan bir nesneye erişildi ( [unowned self] kullanıldı). Sonuç: runtime çökmesi. Çözüm: [weak self] kullanmak ve nil kontrolü yapmak.