Swift Closure Nedir? — Bölüm 2
Hoş geldiniz değerli klavyeşörler. Mücadelemiz sürüyor, karşımızda bölüm sonu canavarı gibi bir şey var. Onu yeniyoruz, prensesi değil kendimizi kurtarıyoruz 🕹️.
Öncelikle eğer bir önceki bölümü anlamadıysanız, ya da hiç okumadıysanız lütfen Swift Closure Nedir sorusunu cevapladığım yazımı okuyun. Öğrenme genellikle adım adım gerçekleşir, bu yüzden basit closure yapılarını anlayabiliyor olmanız oldukça önemli.
Tekrara girmeden ilerleyelim. Çünkü bu yazıda sizler için bolca örnek hazırladım. Bu projeleri indirip, üzerlerinde denemeler yaparak okuduklarınızı pekiştirmeniz faydalı olacaktır.
Bir önceki yazıda basit closure’lar görerek onları fonksiyonlar ile karşılaştırmıştık. Şimdi de bir closure’ın syntax’ını detaylı şekilde ele alarak ilerleyelim. Bu ilerleme esnasında Swift’in bizlere sunduğu sorted(by: )
metodunu kullanacağız.
Bilmeyenler için kısaca bu metodun işlevi, aynı türdeki birden fazla değişkeni sıralamaktır. Yani String
ile String
, Int
ile Int
, Date
ile Date
karşılaştırılarak sıralanabilir. Ancak String
ile Int
farklı türde oldukları için derleme hatası ortaya çıkacaktır. 🔗
Şimdi gelelim örneğimze, aslında aşağıda bulunan 7 farklı satır kod, aynı işlemi yapabiliyor 🤯 Sakince hepsini bir arada görünce, korkulacak bir şey olmadığını anlıyoruz 💪
Sırasıyla ele alalım:
- 1. satırı artık az çok anladığınızı düşünüyorum.
- 2. satırda closure önce değişken tipi bildirmekten kurtuluyor. 🔗
- 3. satırda
return
yani geri dönüş tipini bildirmekten kurtuluyor. - 4. satırda
sorted
methodu(by: )
parametre ismini bildirmekten kurtuluyor. - 5. satırda closure, isimlerinden tamamen kurtuluyor.
- 6. satırda closure,
return
anahtar kelimesinden kurtuluyor. - 7. satırda da artık Allah ne verdiyse geride bırakmış haliyle, en baştakiyle aynı işlemi yapabilen bir closure karşımızda 🫨
Ben bu örnek sayesinde neden bu kadar karmaşık geliyor sorusunu bir nebze olsun anlamıştım, umarım sizde de faydalı olur. Şimdi de işin teorisine göz atalım.
Trailing Closure Nedir?
Farklı bir isme sahip olduğu için başka bir iş yapıyormuş gibi görünse de, trailing closure sadece daha kısa yazılmış bir closure, başka bir şey değil. Özetle, bir fonksiyon, diğer bir fonksiyonu parametre olarak aldığında, trailing closure yazım şeklini kullanarak kodun okunabilirliğini arttırabiliyoruz. Anlaşıldı mı?
Apple dokümantasyonu da şu şekilde tanımlıyor:
Eğer bir fonksiyonun son parametresi olarak closure iletmeniz gerekiyorsa ve closure yazımı uzun ise, bunu trailing closure olarak yazabilirsiniz. Eğer fonksiyonun tek argümanı closure ise, aç-kapa düz parantezleri kullanmanıza da gerek yoktur. 🔗
Yani tekrar edersek, buradaki hedef bir fonksiyonun son parametresi olan closure’ın görüntü kirliliği oluşturmasının önüne geçmek. Tek bir sebep var daha kolay, okunabilirlik. Bunun için closure, fonksiyonun bir parametresi olmasına rağmen parantezin dışında yazılır. Argüman ismi de belirtilmez.
Capturing values ne demektir?
Closure’lar kendilerini çevreleyen bağlamlarda yer alan değişken ve ve sabitleri yakalayabilir. Bu değişken değerlerini kendi gövdesi içinden değiştirebilir. Üstelik bunu, kendisini kapsayan bağlam (Sınıf, yapı) yok olsa bile gerçekleştirebilir. 🔗
Closure dışında yer alan herhangi bir değeri, closure içinde kullandığımız zaman Swift bu değeri yakalar, ve closure ile birlikte depolar. Burada basit de bir örneği var. 🔗
Bu işlem, en sade haliyle nested (İç içe geçmiş) fonksiyonlarda gözlenebilir. İç içe geçmiş fonksiyonlarda içte bulunan fonksiyon, dışarıda yer alan fonksiyonun argümanlarını, değişken ya da sabitlerini kullanabilir. Bu bilgiyi örneklerde daha iyi anlayacağınızı düşünüyorum 🧠.
Escaping closure nedir?
Bu soruyu daha iyi anlamak için de, non-escaping
closure nedir onu da anlamak önemli.
Non-escaping closure’larda çalışma aşağıdaki adımlarda gerçekleşir.
- Fonksiyona argüman olarak closure verilir.
- Fonkisyon işlemlerini yapar.
- Fonksiyon closure’u çalıştırır.
- Fonksiyon
return
eder.
Escaping closure’larda ise çalışma aşağıdaki adımlarda gerçekleşir.
- Fonksiyona argüman olarak closure verilir.
- Fonkisyon işlemlerini yapar.
- Fonksiyon closure’u asenkron olarak çalıştırır, ya da daha sonra kullanmak amacıyla depolar.
- Fonksiyon
return
eder.
Aradaki fark, closure’un içinde bulunduğu fonksiyondan daha uzun yaşayacak olmasıdır. Buradaki @escaping
ifadesi, closure’un içinde bulunduğu fonkisyonun yaşam süresinden daha uzun yaşayabilmek için kaçtığını ifade eder.
Escaping closure, bir fonksiyona argüman olarak verilen, ancak verildiği fonksiyon return ettikten sonra çağırılan closure yapısıdır.
Örnek proje 1: Bu basit örnekte bir playground dosyası üzerinde closure yaşam döngüsü diyebileceğim süreci basit print()
işlevleri kullanarak gözlemleme şansınız var.
Örnek proje 2: Bu örnekte bir SwiftUI projesi üzerinde closureların nasıl değişim ve gelişim yaşayabileceğini gösteren örnekler var. Ek olarak @escaping
closurelarla ilgili ufak bir alıştırma şansı yapmanız mümkün.
Escaping closure, retain cycle, memory leak ilişkisi:
Hatırlayalım memory leak; hafızanın bir bölümünün kullanılması (İşgal edilmesi) ve hiçbir zaman geri salıverilmemesi anlamına geliyor.
Retain cycle ise, birbirine güçlü bir şekilde referans veren iki objenin ARC (Automatic Referance Counter) tarafından hiçbir zaman yok edilmemesi (Deallocate) anlamına geliyor. 🔗
Closure’larda bu durum genellikle şöyle ortaya çıkıyor. Closure self
‘e yani sınıfın varlığına güçlü bir bağ (Strong reference) kuruyor, aynı zamanda sınıf da closure’a güçlü bir bağ kuruyor. Böylelikle otomatik olarak hiçbir zaman yok edilmeyecek bu strong reference, çözümsüz bir döngüyle hafıza kaybına neden oluyor.
Bu da uygulamanın gereğinden fazla hafıza tüketmesine, dolayısıyla yavaşlamasına ve belki de işletim sistemi tarafından kapatılmasına kadar varabilecek sonuçlar doğruyor.
Örnek proje 3: Bu örnekte de 2 ekranlı basit bir uygulama üzerinde memory leak, retain cycle ve [weak self]
ile ilgili bilgilere ulaşabilir, alıştırma yapabilirsiniz.
- Not:
[unowned self]
konusuna bilerek hiç değinmedim. Kafa karıştırmaya şimdilik gerek yok. Bunları anladıktan sonra o çantada keklik.
Hala anlamamış olabilirsiniz ve bu durum gayet normal. Çoğu şeyi ilk denemede anlamıyoruz zaten. Peki o zaman ben nasıl öğrendim? Bunu sizinle paylaşayım👇.
Ben Closure’ları nasıl öğrendim?
Şu anda yazı bitti ama siz closure’ları muhtemelen tamamen anlamadınız.
En aşağıda ilettiğim kaynakları da dikkatlice, kodları yazarak izleyin.
Her biri, farklı farklı closure nedir sorusuna cevap veriyor.
Hepsini saniye saniye izleyip, tüm kodları yazdınız.
O zaman bir defa daha tüm süreci tekrar edin.
Sonrasında bir defa daha.
Sonra bir defa daha.
Sonra bir kez daha.
Sonra bir daha.
Bir daha.
🔂 🔂 🔂
🔂 🔂
🔂
Ve soru işaretiniz kalmayana kadar tekrar edin. İşte bütün mesele bu. Anlaşıldı mı?
Buraya kadar okuduğunuz için tebrik ederim 🥇. İş görüşmesine hazırlanan veya bir yerlerde çalışan ama closure konusu ile tam olarak haşır neşir olmamış, bir türlü kapsamlı ve tek noktada kaynak bulamamış arkadaşlara faydalı bir yazı oldu diye düşünüyorum.
Türkçe ve anlaşılır kaynak eksikliği olduğunu düşündüğüm konularla ilgili yazmaya devam edeceğim. Eğer bu yazıyı faydalı bulduysanız beğenmek, paylaşmak ya da alkış atmak suretiyle destek vermeniz beni mutlu edecektir, nihayetinde alkışlarla yaşıyoruz 🥳.
Sonuç:
Bu yazıyı okuyunca closure konusunda ileri düzeyde bilgi sahibi olduğunuza inanıyorum. Kaynakları okuma ve bolca pratik ile de bu konuyu ‘beyin bedava, attım hafızaya’ şeklinde yerleştirmiş olabilirsiniz 😎.
- Closure ne şekilde karşımıza çıkarsa çıksın, aynı prensiple çalıştığını kavradık 🏋️♀️
- Trailing closure’ın şekilli ismine rağmen sadece kısa yazım olduğunu öğrendik ✍️
- Ve birbiri ile bağlı olan escaping closure, memory leak, retain cycle gibi konuların ilişkisini kuracak bilgiler edindik. Örnek projelere de göz attık tabi 🫡
Bu iki bölümlük seride closure konusunu ele almaya çalıştım. Umarım faydalı olmuştur. Aslında bu konu ile ilgili bir Youtube videosu çekerek örnekleri daha rahat açıklayabileceğimi düşünüyorum.
Her ne kadar README.md dosyalarında adım adım anlattıysam da, izleyerek ve dinleyerek daha iyi öğrendiğini düşünen (Benim gibi) bir sürü insan olduğunu biliyorum. İlerleyen günlerde zaman bulabilirsem bunu da yaparım.
Anlamadığınız, açık olmadığını düşündüğünüz ya da gözden kaçırdığıma inandığınız yerlerle ilgili benimle çekinmeden bağlantı kurabilir, closure’ları daha da iyi anlamama yardım etmek, soru sormak ya da düzeltme yapmak isterseniz de irtibata geçebilirsiz.👇
https://www.linkedin.com/in/eyupmert/
Bu yazımı faydalı bulduysanız e-posta bültenime kayıt olup diğer yazılarıma da göz atabilirsiniz. Kendinize iyi bakmayı ihmal etmeyiniz 🫶
- Not: Örnek projeleri kendi GitHub hesabımın çerçevesini korumak adına İngilizce dilinde oluşturdum. Ancak ben hiç İngilizce bilmiyorum diyorsanız, yorum satırlarını ve README.md dosyalarını Google Translate ile Türkçe’ye çevirerek okuyabilirsiniz.
Kaynaklar:
https://www.hackingwithswift.com/sixty/6/12/closures-summary
https://www.avanderlee.com/swift/trailing-escaping-closures/
https://www.youtube.com/watch?v=4-EvBzIT5Y0&list=PPSV&ab_channel=StewartLynch
https://www.youtube.com/watch?v=7gg8iBH2fg4&list=PPSV&ab_channel=SwiftfulThinking
https://www.youtube.com/watch?v=vmgxTNwLlQY&list=PPSV&ab_channel=SwiftandTips
https://www.youtube.com/watch?v=-T_Kp6-RRDM&ab_channel=MichaelLin
https://www.youtube.com/watch?v=5ePkdcPMZ0M&list=PPSV&ab_channel=iOSAcademy
https://www.youtube.com/watch?v=HnIID4W3a_o&ab_channel=PaulHudson
https://www.youtube.com/watch?v=fs1_s39pMZc&list=PPSV&ab_channel=EssentialDeveloper
https://www.youtube.com/watch?v=fwyp9yck8QY&list=PPSV&ab_channel=SwiftArcade