Giriş seviye Closure’ları 4 ana başlık altında örnekler vererek anlatmaya çalışacağım. Keyifli okumalar!
1- Giriş
- Closures Tanımı
Kısaca: Closure’lar daha esnek ve modüler bir yapı kurmanızı sağlayan kod bloklarıdır. Yeniden kullanılabilir, okunması kolaydır ve aktarılabilir.
- Neden Closures Kullanmalıyız?
- Kodlarımızı daha modüler hale getirerek süreçlerimizi kolaylaştırabiliriz. Peki modüler yapı ne demek? Projeyi veya kodlarınızı bileşenlere ayırmanızı sağlar ve böylece her bir bileşen sadece belirli bir görevi üstlenir. Bu da kodun daha okunaklı, anlaşılır, genişletilebilir ve bakım yapabilir hale getirmiş olur.
- Özellikle Asenkron işlemler yapıyorsanız (mesela ağ isteklerinde ve veri tabanı işlemlerinde çok kullanırız) bir işlem tamamladığında süreci devam ettirebilmek için çok işimize yarar. (Swift 5.5’te gelen async wait ile bu işlemi daha az kod ile yapabilir hale geldik fakat düşük iOS sürümlerini desteklemiyor… )
- Parametre olarak başka fonksiyonlara aktarım sağlayabiliyoruz ve ayrıca bağımlılığı düşük olduğu için bağımsız ve taşınabilir kod parçaları oluşturabiliyoruz. Bu da kodumuzu daha dinamik bir hale getirmiş oluyor.
- Closures ve Fonksiyonlar: Farklılıklar ve Benzerlikler
- Benzerlikler
- Her ikisi de belirli bir işlemi yerine getirir.
- Her ikisi de parametre alabilir.
- Her ikisi de değer döndürebilir. (return)
- Farklılıklar
- Fonksiyon ayrı bir blokta tanımlanabilir ve blok içerisinden çağrılır. Closure ise her hangi bir değişkene atanabilir ve başka fonksiyona parametre olarak tanımlanabilir.
- Fonksiyonları isimlendirmek zorundayız fakat Closure’ların ismi olmasada olur.
- Fonksiyonlar genel olarak belirli bir işi yerine getirir, Closure’lar ise callback işlemlerinde kullanmak için idealdir.
- Benzerlikler
Buraya kadar okudunuz, az çok fikir sahibi oldunuz ama okuduklarınızı pekiştirmezsek aklınızdan uçup gidecektir. O yüzden aşağıdaki kod örneklerini sizde yeni bir proje açıp tekrar tekrar deneyin. Benim yazdıklarıma bağlı kalmadan bağımsız kodlar yazıp aldığınız hatalarla konuyu daha iyi anlayın. Bu hataları çözdükçe konuyu öğrenmiş olacaksınız 🙂
2- Closures nasıl oluşturulur? Örneklerle kullanımını açıklayalım.
Closure’ı oluşturma Syntax’ı
Aşağıdaki kod genel olarak Closure’un yazılış şeklidir. Burda sadece syntax’ı görseniz yeterli.
Parametresiz Closures
Parametresiz Closure aşağıdaki gibi oluşturulur. Her hangi bir değer almaz sadece kod bloğu çalışır ve bize bir değer döndürür.
Bir Closure’u değişken olarak oluştabiliriz demiştik. Aşağıdaki değişkenin yapacağı işlem 3 satırda da aynı. Burada tanımlama işlemini Void, () ve _ ile sağlayabiliriz. Bu ne demek derseniz bize bir blok aç, değer döndürmene gerek yok demek oluyor. Daha sonra değişkenimizi çağırıyoruz.
Parametre Alan Closures
( ) içerisine bir parametre vereceğimizi söylememiz gerekli. Mesela bu Closure’un bir String ifade döndürmesini istiyoruz. Parametre alanına bunu yazdık ve daha sonra Closure’u çağırdığımız yerde içerisine değer atadık.
Dönüş Değeri İçeren Closures (Return Value)
Bir Closure oluşturalım, bu sefer : () -> Void, (String) -> Void gibi bir type tanımlamayalım. Biliyorsunuz ki Swift Strong-Type bir dildir. Yani bir değişkenin kimliğini söylemezseniz veya bir şekilde ona Type atamazsanız hata alırsınız. İki durumu da inceleyelim.
İlk örnekte Type belirlemedik çünkü alabileceği parametreyi String olarak tanımladık. Yani aslında biz closure değişkenine sen (String) alıp, -> String döndüreceksin demiş olduk. Bu yüzden tanımlama ihtiyacı duymamış olduk. İkinci örnekte Type’ın tanımlanmış haline bakabilirsiniz. Aşağıda ilk örneğin tanımına bakarsak Type’ının otomatik belirlendiğini görebilirsiniz.
3- Closures İşlevleri ve Kullanım Alanları
Closures ile Sıralama (Sorting)
Elimizde data ismiyle oluşturduğumuz Int değer alan array’imiz var. Biz bu array’i sıralamak istediğimizde sorted metodunu kullanırız. Yukarıdaki kod bloğunda sorted metodunun tanımında aslında bir closure istediğini görüyoruz. Aslında siz bilmeden closure’lardan yardım alıyordunuz.
Yukarıdaki kodlara bakarsak Closure syntax’ını karşıladığını görebiliriz. O zaman biz yukarıdaki ifadeyi kendi Closure’umuzu oluşturarakta kullanabiliriz.
sortClosure 2 tane integer değer alıp geriye Bool bir değer döndürüyor. Bir üstteki kod bloğunda sorted metodunun bizden nasıl bir closure istediğine bakarak yazdık.
Peki neden bunu kullanayım ki? Yukarıda modüler yapıdan bahsetmiştik. Projede tek bir sayfada 2000+ kod satırı var diyelim ve o sayfadaki tüm sıralama işlemleri hatalı kodlanmış ve siz bu projeyi yeni devir aldınız. Sizce 2000+ satır içerisindeki tüm sorunları yakalamak mı daha kolay yoksa tek bir closure ifadesinin içerisini fix’lemek mi? Tabikii closure 🙂 Bu örnek çok basit kaçabilir ama olayın mantığı için basit ifadelerle anlatmak gerek.
Haritalama (Mapping) ve Filtreleme (Filtering) İşlemleri
Mapping ve Filter işlemlerinde kullandığımız metodlar yine Sorted metodundaki gibi closure almaktadır. İlk önce map metodu ne istiyor ona bakalım.
Bizden integer bir değer alıyor ve T type olarak return ediyor. (T type kısaca her hangi bir tip alabilir fakat bunu belirtmelisin demek. Başka yazımda anlatacağım şu an konumuz değil)
O zaman biz map metodunu hiç özelleştirmeden kullanalım nasıl bir sonuç ortaya çıkacak. Aşağıdaki işlemde yine aynı data array’imizi kullandık. Beklediğim işlem çift sayıları bulmak ve tek sayıları 0 olarak değiştirmek daha sonrada mappedData’ya eşitleyip ekrana bastırmak. map, data array’inin içerisindeki elemanları gezerek value değerini elde eder, elde ettikçe gerekli kontrolleri sağlayıp o değer için return işlemi sağlayıp mappedData’ya ekler.
Kendi closure’umuz ile bu işlemi oluşturalım. Yine çıktılarımız aynı. Hiç bir şey değişmedi.
Filter metodu ne istiyor ona bakalım.
filter metodu bizden int değer istiyor daha sonra da Bool bir değer döndür diyor. Bu işlemdeki true/false’a göre de bize filtrelenmiş bir [Int] array döndürecek. O zaman bu sefer ilk önce kendi closure’umuzu yazalım.
“var filteredData = …. ” satırını okumamız daha kolay ve anlaşılabilir olduğunu ve verdiğimiz closure ifadesinden bu metodu yönetebildiğimizi görüyoruz. Bu da kodumuzun kalitesini arttırmış oluyor. Şimdi bir de closure’u özelleştirmeden yazalım.
1.yol evet çok kısa bir yazım şekline sahip, fakat basit bir işlem yaptık sadece data’mızın içerisindeki çift ifadeleri bulduk. Ama işlemlerimiz karmaşık bir hal alsaydı burayı okumamız daha zor olacaktı. 2.yol da ise klasik bir kod parçası görüyoruz. Neden Closure kullandığımızı Sorting’i anlatırken söylemiştim.
4- Geri Arama Fonksiyonları (Callback Functions)
Callback’ler, bir işlem tamamlandığında veya bir olay gerçekleştiğinde başka bir işlevin çağrılmasını sağlayan mekanizmalardır.
Bir fonksiyon da geriye callback döndürme işlemini closure ile yapabiliriz. Mesela bir validation ismi ile fonksiyon oluşturalım burada bir dizi işlem sonrası bize callback ile true veya false dönen bir metod yazalım. Fonksiyonun amacı iki tane string ifadenin birbiri ile eşit olması durumunda ekrana başarılı veya başarısız diye log bastırması olsun.
Aşağıdaki kod bloğu tanıdık geldi dimi 🙂 Parametre alan Closure syntax’ımız. Gelen status değerine göre log’a string bastırıyor.
Şimdilik giriş seviyesi için bu bilgiler yeterli diye düşünüyorum. İleri seviye Closure başlıklı yeni bir yazı paylaştığımda bu konunun altına ilgili yazının linkini bırakacağım.
Sağlıcakla kalın!
Bir yanıt yazın