Swift | Closure

cemal tüysüz
4 min readNov 27, 2022

--

Herkese selamlar, bu yazıda swift ile programlama yaparken kullanışlı ve güçlü bir yapı olan closure dan bahsediyor olacağız. Diğer yazılarda da olduğu gibi temelden giriş yapıp ilerliyor olacağız.

Closure

Closure yapısı tekrar ve tekrar yürütebileceğiniz kod bloklarının ta kendisidir. Hani bir fonksiyon oluştururken fonksiyona işlevsellik katması için süslü parantezlerimizi açıyoruz ve içine kodumuzu yazıyoruz ya. İşte bu kod bloğuna closure gözüyle bakabiliriz.

Closure yapısı %50 fonksiyon %50 değişken gibidir. Bir closure aynı fonksiyon gibi sizden parametre alabilir veya kod bloğu sonlandığında size bir parametre dönmesini sağlayabilirsiniz. Daha fazlası ise bu kod bloğunu bir sabite veya değişkene atayabilirsiniz.

Basit Closure

Yukarıda closure yapısının belki de en basit halini görüyorsunuz. Elimde bir adet kod bloğu var ve bu kod bloğunu birinci satırda bir sabite atıyorum sonrasında bu sabiti çağırarak kod bloğunu çalıştırmış oluyorum.

Şimdi de bunu bir tık değiştirelim.

Bu sefer sabiti bir değişkene çevirdik.Kod bloğunu 5. satırda değiştirdik ve kod bloğunu yürüttüğümüzde çıktının en son atadığımız kod bloğundan geldiğini gördük.

Parametreli ve Dönüşlü Closure

Satır 1 ve 5 de sabit iki farklı closure oluşturdum. Bu fonksiyonların type kısmını verirken özellikle daha anlaşılabilir olmaları için parantezleri boşluklu bir biçimde oluşturdum.

Bir closure tipi girdi ve çıktı belirtilerek oluşturulur. Örnek üzerinde Closure 1 yapısı oluşturulurken ilk parantez içerisinde String yazılarak bu kod bloğuna bir String iletilmesi gerektiği belirtildi. Dileseydik araya virgül koyarak daha fazla parametre de ekleyebilirdik. Ok işaretinden sonra dönüş tipini belirtmemiz gerekiyor. Kod bloğunun bir parametre döndürmesini istemiyorsak Void yazabilir veya closure2 deki gibi parantez içini boş bırakabiliriz.

Closure3 de ise ilk yuvada bu kod bloğunun 2 adet Integer alacağını ve ikinci yuvada da bu kod bloğunun bir Integer return edeceğini belirttik. Kod bloğunda aynı bir fonksiyon gibi iki sayıyı toplayıp return ettik.

Parametre İsmi Vermeden Closure Kullanımı

Kod bloğuna parametre gönderdiğimizde bu parametreleri isimlendirip in keywordu ile kullanıyorduk. Bunu da yapmak zorunda değiliz aslında. Birinci parametre için $0, ikinci parametre için $1 şeklinde kullanımlar da yapabiliriz. Aşağıdaki kod örneğini inceleyelim.

Kuvvet adlı closure için iki adet sayısal değeri parametre olarak alıyoruz. Birinci değere $0 ve ikinci değere $1 ifadeleri ile ulaşıyoruz. Bu şekilde closure oluşturma tek parametreli yapılarda daha iyi durabilir. Lakin closure yapınız çok parametreli ise daha temiz ve anlaşılabilir olması için isimlendirme ile parametre kullanımı uygun olacaktır.

Fonksiyon + Constructor + Closure

Bu kısımda ise closure parametreli fonksiyonlar ve constructor (initializer) oluşturacağız.

Satır 1 de yer alan fonksiyon bizim için apiden veri getirecek bir fonksiyon olsun. Bizim amacımız ise network isteğinin bitip bitmediğini algılamak. Bu durumda parametre olarak bir closure aldık. İstek tamamlandığı zaman bu closure u çağırarak kod bloğunun çalışmasını sağlayabilir, dolayısıyla da isteğin bittiğinden haberdar olabiliriz.

Bunu bir de bir sınıfın yapıcı methodu ile gerçekleştirelim.

MyClass adında bir sınıf oluşturdum. Bu sınıf bellekten uçacağı zaman sınıfın oluşturulduğu yere haber verilmesini sağlamak için init fonksiyonu opsiyonel olarak closure istiyor. 14. satırda bu sınıftan bir adet nesne oluşturuyorum ve 18. satırda sınıfı bellekten uçurmak için nil ataması yapıyorum. Sonuç olarak sınıfın oluşturulduğu kapsam bu durumdan haberdar oluyor.

Parametre olarak istenilen closure yapısının girdisi ve çıktısı başka bir fonksiyon ile aynı ise direkt olarak o fonksiyon da çağırılabilir. Aşağıdaki örneği inceleyelim :

Trailing Closure

Bir fonksiyon son parametresinde closure istiyorsa bu closure o fonksiyonun gövdesiymiş gibi kullanılabilir.

Aşağıdaki örneği inceleyelim:

Database üzerinden veri getirmek istiyoruz. Parametre olarak bir tane query ve işlemin tamamlandığını bildiren bir tane closure isteniyor. Burada yer alan closure son parametre olarak istendiği için Trailing Closure olarak kullanılabilme özelliğine kavuşuyor.

Sanki getDataFromDB fonksiyonunun gövdesiymiş gibi parametrelerin verildiği yuvarlak parantezlerin dışında closure bloğu açılabilir duruma geldi.

@escaping & @nonescaping Closure

Bir fonksiyon çalışmasını bitirene kadar parametre olarak aldığı closure yapısını bellekte saklar. Çalışmasını bitirdiğinde closure bellekten uçar. Bu default bir durumdur. Bu tarz closure yapıları @nonescaping dir. Yani yok oluştan kaçamazlar.

Bazı durumlarda da fonksiyon çalışmayı bitirdiğinde hemen yok olmasın isteriz. Bunun sebebine örnek olarak async devam eden işlemin sonucunda bu closure çağırılmak istenir lakin çoktan bellekten uçmuş olma olasılığı ile hata alınabilir. Bu tarz durumlarda @escaping kullanırız.

Başa bir örnekte ise notification center tarzında bir yapı oluşturmak istiyorsunuz. Bir key ile dinleyici oluşturmak ve başka bir kapsamdan aynı key ile bir post işlemi gerçekleştiğinde dinleyicinin bunu algılamasını istiyorsunuz.

Satır 6 da oluşturduğum sınıf Observer ilişkisi ile oluşturulmuş basit bir sınıf. Sınıfın amacı çok farklı bağlamların bile bir anahtar aracılığı ile birbiriyle iletişimde olmasını sağlıyor. Bu farklı bağlamlar fonksiyonlar, sınıflar veya modüller bile olabilir.

Sınıfın 12. satırda addObserver diye bir fonksiyonu bulunuyor. Dikkat ettiyseniz bu fonksiyon bir key ve birde @escaping closure almakta. Bunun nedeni ise bu key ve closure satır 10 daki array de bir arada satır 1 de oluşturulan observer sınıfı aracılığı kapsüllenip saklanacaklar. Birisi bu fonksiyonu farklı bir scope üzerinden tetiklemek istediğinde bu keyi vermesi yeterli olacak. Satır 20 deki gibi verilen key ile liste içerisindeki closure lar alınıp hepsi çalıştırılıyor ve dolayısı ile dinleyicilere haber verilmiş olunuyor.

Bu işlemlerin tamamını yapabilmek için fonksiyonda verilen closure yapısının destroy olmaması gerekirdi. Bellekten uçmaması adına @escaping ifadesi eklendi.

Yukarıda yazdığımız kodu çalıştıralım :

Umarım yazı faydalı olmuştur. Bir sonraki yazıda swift ile map, compactMap, flatMap veya filter gibi bir çok ileri düzey fonksiyonlara değinip bazılarını ise kendimiz yazıyor olacağız. Yeni yazılardan haberdar olmak için takip edebilirsiniz.

Sağlıcakla kalın.

--

--