Merhaba arkadaşlar ,
mobilhanem.com sitemiz için anlattığımız/yayınladığımız Swift Dersleri serimize bu yazımızda Swift Closure Kullanımı ile devam edeceğiz. Bir önceki yazımızda Swift Function Kullanımı konusundan bahsetmiştik. Bu derse başlamadan önce xcode’u kurmak ve playground üzerinde swift kodu yazabilmek için bu dersimizi okumanızı tavsiye ederim.
Swift Closure Nedir ?
Bir önceki dersimizi okuduysanız bu dersimiz sizi çok zorlamayacaktır. En kaba haliyle Closure ‘ler fonksiyonların daha kısaltılmış halleridir diyebiliriz. Closure ‘lar değişkenlerde saklanabilirler ve aynı zamanda bir fonksiyona parametre olarak verilebilirler. Lafı çok uzatmadan kodlarımızı yazmaya başlayalım 🙂
İki Sayıyı Toplama İşlemi
Hemen nerden çıktı bu diye söylenmeyin 🙂 Şimdi iki sayıyı toplayan bir fonksiyon yazacağım ardından ise iki sayıyı toplayan bir closure yazacağım bu şekilde farkını daha net görebileceğiz.
func topla(_ sayi1: Int, _ sayi2: Int)-> Int{ return sayi1 + sayi2 }
Evet iki sayıyı toplayıp geriye döndüren fonksiyonumuzu yazdık. Burada ki _ sembolünün ne işe yaradığını bilmiyorsanız veya fonksiyonlar hakkında bilgi sahibi değilseniz bu yazıyı okumayı bırakıp okuyup geri dönebilirsiniz. Evet şimdide fonksiyonumuzu çağırıp, fonksiyonumuzdan dönen sonucu bir değişkene atıp ekrana bastıralım ,
var sonuc = topla(10, 20) print(sonuc)
Evet fonksiyon kullanarak işlemimizi bu şekilde gerçekleştirdik. Peki Closure kullanarak nasıl yapabiliriz ?
Closure Kullanarak
Hemen iki sayıyı toplayıp sonucu geriye döndüren closure ‘ımızı yazalım ,
var closureIleToplama : (Int,Int) -> (Int) = { sayi1 , sayi2 in return sayi1 + sayi2 }
Syntax ‘ı biraz garip gelebilir ama korkmayın zamanla alışıyorsunuz. Evet burada ismi closureIleToplama olan bir closure oluşturduk. Ve oluştururken closure ‘ımızın parametre olarak iki adet Int alacağınız ve geriye Int türünde değer döndüreceğini belirttik. Closure tanımlamalarında bunları belirtmek zorundayız. Ve ardından ilk parametremizin adının sayi1 olduğunu ikinci parametremizin ise isminin sayi2 olduğunu belirttik ve daha sonra return keyword ‘ü ile bu iki değerimizin toplamını geriye döndürdük. Closure ‘larda fonksiyonlar gibi çağrıldığında çalışırlar. Şimdi oluşturduğumuz closureIleToplama isimli closure ‘ımızı çağıralım ve parametrelerimizi verelim,
closureIleToplama(10,20)
Ve sonuc olarak 30 değerini gördük yazdığımız closure sorunsuz çalışıyor . Yazdığımız bu closure ‘ı daha da kısa olarak yazabilmemiz mümkündür,
var closureIleToplamaKısa : (Int,Int) -> (Int) = { return $0 + $1 }
Daha öncedende söylediğim gibi closure ‘a verilecek olan parametre ve dönüş tiplerini her zaman belirtmek zorundayız. Burada farklı olarak verilecek olan ilk parametremizin ismini ve ikinci parametremizin ismini belirtmedik. Bunun yerine $0 ve $1 ile gösterdik. $0 bizim ilk parametremizi, $1 ise ikinci parametremizi temsil etmektedir. Bu şekilde belirttiğimizde derleyicimiz $0 ‘ın ilk parametreye, $1 ‘in ikinci parametreye denk geldiğini bilmektedir.
Fonksiyon’a Parametre Olarak Closure Nasıl Verilir ?
Evet şimdi örneğimizi ilk olarak fonksiyon şeklinde oluşturalım. Bir fonksiyonumuz olsun ve bu fonksiyonumuz parametre olarak aldığı bir değer ile yine parametre olarak aldığı bir array içerisindeki elemanları karşılaştırsın ve geriye filtrelenmiş bir array döndürsün. Döndüreceği array ‘in elemanları ise şu koşulu sağlasın, input olarak verilen array ‘in hangi elemanları, input olarak verilmiş olan değerden büyük ise onları döndürsün.
func buyukOlanlariFiltrele(deger: Int, sayilar: [Int]) -> [Int] { var filtrelenmisDizi = [Int]() for sayi in sayilar { if sayi > deger { filtrelenmisDizi.append(sayi) } } return filtrelenmisDizi }
Evet ismi buyukOlanlariFiltrele olan fonksiyonumuzu yazdık. Fonksiyonumuz parametre olarak Int türünde bir deger ve Int degerlerden olusan bir dizi almaktadır bu diziyide fonksiyonumuzun içerisinde sayilar ismi ile kullanacağız. Fonksiyonumuzun içerisinde hemen geriye döndüreceğimiz filtrelenmiş olacak dizimizi filtrelenmisDizi ismi ile oluşturduk. Ve ardından hemen sayilar isimli dizimiz içerisindeki elemanlara erişebilmek için döngümüzü yazdık.
Bu for döngüsünü daha önceki derslerde anlatmıştım. Kısaca sayilar dizisi içerisindeki her bir elemana sayi diyoruz. Ve ardından bir if koşulu bulunmakta, bu if koşulu ise filtreleme işlemini gerçekleştireceğimiz yer. Bu koşulda sayilar isimli dizinin bir elemanı input olarak verilen deger ‘den büyük ise koşul sağlanmış olacaktır ve bloğun içerisine girecektir.
Bloğumuzun içerisindede geriye döndüreceğimiz ve daha önce oluşturduğumuz filtrelenmisDizi isimli array ‘imize .append methodu ile koşulumuzu sağlayan sayıyı yani kodumuzun içerisindeki ismi sayi olan değeri dizimize ekliyoruz. Ve bu işlem sayilar isimli dizinin bütün elemanlarını gezene kadar devam ediyor böylece amacımızı gerçekleştirmiş oluyoruz. Şimdi ise bu fonksiyonumuzu çağıralım ve sonucunu görelim ,
let filtrelenmisler = buyukOlanlariFiltrele(deger: 3, sayilar: [1,2,3,4,5,10]) print(filtrelenmisler)
Fonksiyonumuzu çağırdık ve deger olarak 3 ve dizi olarakta [1,2,3,4,5,10] değerlerini içeren bir dizi verdik. Fonksiyonumuz bu dizi içerisindeki bütün elemanları karşılaştıracak ve 3 ‘ten büyük olanları filtrelenmisDizi ‘ye ekleyecek ve geriye döndürecektir. Ve geriye dönen bu dizi filtrelenmisler isimli değişkenimize atanacaktır. Ve ardındanda print komutu ile ekrana bastırılacaktır. Çıktı olarak 4,5,10 değerlerini içeren bir dizi görmemiz lazım 🙂
Eğer 5’ten Küçük Değerleri İsteseydik ?
Bu durumda kodumuzda nereleri değiştirmemiz gerekecekti ?
İlk olarak parametre olarak verdiğimiz deger ‘i 5 olarak değiştirmemiz gerekecekti, ardından if koşulumuz içerisinde bulunan > sembolünü, < sembolü ile değiştirmemiz gerekecekti. Ve son olarakta fonksiyonumuzun ismini mantıklı olması açısından kucukOlanlariFiltrele tarzında bir isim ile değiştirmemiz gerekecekti. Bunun üstüne fonksiyonumuzu çağırdığımız bütün yerlerde değiştirmemiz gerekecekti 🙁 Peki bu durumu nasıl düzeltebiliriz ? İşte çözümü,
İlk olarak filtrelenmiş elemanları dizimize ekleyen ve parametre olarak closure alan fonksiyonumuzu yazalım,
func closureIleFiltreleme(closure: (Int) -> Bool, sayilar: [Int]) -> [Int] { var filtrelenmisDizi = [Int]() for sayi in sayilar { if closure(sayi) { filtrelenmisDizi.append(sayi) } } return filtrelenmisDizi }
Fonksiyon ile filtreleme işlemini yaptığımız örnekten farkı, parametre olarak closure almakta aldığı closure ise Int türünde parametre alıp Boolean(true, false) türünde değer döndürmektedir ve if koşulu ile filtreleme işlemini yaptığımız yerde closure(sayi) ifadesi ile bu boolean değerini kullanarak if koşulunu sağlayıp sağlamadığına bakılmaktadır. Peki bu boolean değeri nerden dönüyor ?
let filtrelenmisler = closureIleFiltreleme(closure: { (sayi) -> Bool in return sayi > 2 }, sayilar: [1, 2, 3, 4, 5, 10])
filtrelenmişler değişkenimize closureIleFiltreleme fonksiyonundan dönen diziyi atadık. Fonksiyonumuza parametre olarak closure ‘ımızı verdik ve parametre olarak sayi alacağını ve geriye boolean türünde değer döndüreceğimizi belirttik ve ardından input olarak gelen sayi isimli değişkenimizi istediğimiz bir koşula tabi tutarak (burada >2 koşulu yani sayilar dizisi içerisindeki elemanların 2 ‘den büyük olma durumu) boolean türünde değer döndürdük. Diğer bir parametremiz ise sayilar isimli 1,2,3,4,5,10 değerlerini barındıran dizimizdir. Bu diziyide tıpkı closure ‘ı parametre olarak verdiğimiz gibi parametre olarak vereceğiz.
Çalışma Mantığı
Buradaki çalışma mantığı ise closureIleFiltreleme fonksiyonumuza parametre olarak closure ve sayilar dizimizi vermekteyiz. sayilar dizimizin içerisindeki her bir elemana sayi diyerek bütün dizimizi dolaşmaktayız. Ve her sayi ‘yı closureIleFiltreleme fonksiyonumuzda tanımladığımız closure ifademizde tanımladığımız (Int) -> Bool durumuna uygun olarak input olarak vermekteyiz. (Int) -> Bool ifadesi ile ilk defa karşılaştıysanız bir önceki dersimi okuyabilirsiniz. Ve bu closure input olarak aldığı sayi ‘yı belirli bir koşul için karşılaştırarak geriye değer döndürmektedir. Burada bu işlem return sayi > 2 ile sağlanmaktadır. Bu bize true veya false değerini döndürecek ve closureIleFiltreleme fonksiyonumuzun içerisindeki if koşulu buna göre sağlanacaktır. Eğer true değeri döner ise, true değeri hangi sayi için döndüyse o değeri filtrelenmisDizi isimli dizimize append fonksiyonu ile ekliyoruz ve bu işlemi paremetre olarak verdiğimiz sayilar isimli dizinin bütün elemanlarını gezmiş olana dek devam ettiriyoruz. En sonunda ise return filtrelenmisDizi komutu ile filtrelenmisDizi ‘tizi filtrelenmişler değişkenimize atıyoruz.
Ve böylelikle kodumuzda değişiklik yapmamız gerektiği zaman sadece closure ‘ımızda hangi koşulu istiyorsak sadece onu değiştirmemiz yeterli olacaktır.
5 ‘ e Bölünebilen Sayıları Filtreleyen Closure
Şimdi de elimizdeki bir dizi içerisinde 5 ‘e bölünebilen sayıları bir dizide birleştirelim ,
func beseBolunebilenler(sayi: Int) -> Bool { return sayi % 5 == 0 }
İlk olarak beseBolunebilenler isminde parametre olarak Int türünde değer alan ve Boolean türünde geriye değer döndüren fonksiyonumuzu tanımladık geriye ise döndürme koşulu sayi % 5 == 0 ifadesi ile sağladık . Bu ifade sağlanıyor ise geriye true, sağlanmıyor ise geriye false değerini döndürecektir. Ve böylece sayi ‘nin yeni diziye eklenip eklenmiyeceğine karar verilecektir. Bu kararı veren ise yukarıda tanımladığımız closureIleFiltreleme fonksiyonudur.
Şimdi ise closureIleFiltreleme fonksiyonumuza parametre olarak beseBolunebilenler fonksiyonumuzu verelim. Bu fonksiyonu closure parametresi olarak verebilmek için tanımladığımız (Int) -> Bool parametre ve dönüş tiplerinin uyuşması zorunludur. Burada bizim beseBolunebilenler fonksiyonumuzda (Int) -> Bool tipindedir. Bu sayede parametre olarak verebilmekteyiz. Diğer bir parametre olarakta 5 ‘e bölünüp bölünemeyeceğini kontrol edeceğimiz dizimizi vermemiz gerekmektedir.
let filtrelenmisDizi = closureIleFiltreleme(closure: beseBolunebilenler, sayilar: [20, 30, 1, 2, 9, 15])
Buradaki çalışma mantığıda yukarıda anlattığım gibi olacaktır. sayilar dizimizin içerisindeki her bir elemanın 5 ‘e bölünüp bölünemediğini kontrol edicek eğer bölünüyorsa true değeri dönecek ve koşul sağlanacak ve o sayi, filtrelenmisDizi ‘mize append fonksiyonu ile eklenecektir. Bu örnekleri kullanarak daha fazla örnek kendiniz düşünüp yapabilirsiniz.
Ve böylelikle bir dersin sonuna gelmiş bulunmaktayız. Sormak istediklerinizi yorum kısmından sorabilirsiniz 🙂
print(“The ability of discerning high quality unavoidably implies the ability of identifying shortcomings.“)
print(“Edsger Dijkstra“)
Burada yaptığım örneklerin kodlarını linke tıklayarak indirebilirsiniz.