Swift Closure

Burak Gül
14 min readOct 16, 2023

--

Merhaba arkadaşlar , bir süredir swift öğreniyorum öğrenirken anlamaya çalıştığım konulardan birisi olan Closure’u anlatmaya çalışacağım.

Photo by Medhat Dawoud on Unsplash

Closure nedir ?

“Group code that executes together, without creating a named function.” diyor Apple. Çevirdiğimizde Adlandırılmış bir fonksiyon oluşturmadan birlikte execute edilen (yürütülen) grup koddur’ ile karşılaşıyoruz. Yani Closure’lar isimsiz fonksiyonlardır diyebiliriz.

Closure’lar 3 formdan birini alırlar :

1 - Global Functions : ismi olan ve hiçbir değer yakalamayan (Capture) Closure’lardır.

2 - Nested Functions : ismi olan ve kendilerini kapsayan (Enclosing) fonksiyondan değerleri yakalayabilen Closure’lardır.

3 - Closure Expressions : kendilerini çevreleyen bağlamdan değerleri yakalayabilen hafif bir söz diziminde (Lightweight syntax) yazılmış isimsiz Closure’lardır.

Swiftin Closure ifadeleri , yaygın senaryolarda kısa ve karmaşık olmayan söz dizimini (syntax) teşvik eden optimizasyonlarla birlikte temiz ve anlaşılır bir stile sahiptir. Bu optimizasyonlar şunlardır :

1- Inferring parameter and return value types from context : Yani bağlamdan parametre ve return value tür/tip/type ını çıkarma.İlerleyen kısımlarda da göreceksiniz bu optimizasyon sayesinde parametre türlerini yazmamıza gerek kalmayacak.

2 - Implicit returns from single expression closures : Yani tek ifadeli closure’lardan örtülü/kesin olarak return etme.Bu optimizasyon sayesinde closure içinde tek satır var ise ve burada return etmemiz gerekiyorsa return keyword’ünü yazmamıza gerek kalmayacak.

3 - Shorthand argument names : Değişken adlarının kısa gösterimi.Bu optimizasyon sayesinde değişken adlarını uzun uzadıya yazmak yerine $0,$1,$2 … şeklinde kısaltarak yazacağız.High order functions da bunları daha çok kullanırız.

4 - Trailing closure syntax : Sondaki closure sözdizimi.Bir fonksiyon parametre olarak iletilen closure son parametre ise fonksiyon parantezlerinin ‘()’ dışına taşıyabiliyoruz bu closure ifadesini. Peki neden bunu yapıyoruz ? Cevabı çok basit eğer tek satıra sığmıyor ise closure’umuz okuması ve anlaşılması zor oluyor.İşimizi kolaylaştırmak için yapıyoruz yani.

Closure ifadelerini nasıl yazarız ?

Buradaki “in” keyword’ü bize , Closure gövdesinin başlangıcını ifade etmekle birlikte closure parametrelerinin ve return type tanımlamalarının bittiğini ve closure’un gövdesinin başlamak üzere olduğunu söyler.

Closure’lara isimsiz fonksiyonlardır dedik , o halde fonksiyonların yaptıklarını yapabilmeliler.Bir parametreye sahip olabilir/olmayabilir , return type (dönüş tipi) ına sahip olabilir/olmayabilir.Closure’ları isimlendirebilir ve o şekilde de çağırabiliriz ve fonksiyondan farkları kalmamış gibi oluyorlar.

Fotoğrafta görükse de gerçek kod üzerinde görmek daha da anlamamıza olanak sağlayacaktır.Şimdi kod kısmına geçelim.

Parametre adını ve dönüş tipini silerek yazdım.Çünkü parametresi ve dönüş tipi olmasın istiyorum.

var introduceYourself = { () ->  in
print("Hello friends i am Burak Gül")
}
introduceYourself()

burada şu hatayı verecektir :

Sebebi ise return arrow (dönüş oku)’dan sonra bir ifade beklemesidir.Kaldıralım ve sonucuna bakalım

Hata yok evet ama “() in ” bunlar boşa duruyor.Sildiğimizde bir sıkıntı çıkmayacaktır, sebebi ise parametre vermiyoruz o yüzden “()” parantezlere gerek yok. “in” keywordünü silmemizin sebebi ise “in” keywordü bize parametre ve dönüş tiplerinin tanımlasının bittiğini ve closure’un body(gövdesi)’sinin başladığını söylüyordu.Closure ifadesi tamamen gövdesinden oluştuğu için de “in” keywordü atlanabilir.Son hali ise aşağıdadır.

Şimdi ise parametre alan ama dönüş tipi olmayan şekilde yapalım.

var introduceYourself = { (name : String)  in
print("Hello i am \(name)")
}
introduceYourself("Burak Gül")
// output is
// Hello i am Burak Gül

Devam edelim parametre alan ve dönüş tipine sahip olan bir closure ile.

var introduceYourself = { (name : String,birthYear:Int) -> (String) in
return "Hello i am \(name) and i am \(2023-birthYear) years old"
}
var introduceYourselfText = introduceYourself("Burak",2001)
print(introduceYourselfText) // output is Hello i am Burak and i am 22 years old

Yukarıdaki closure’ları kullanabilmem için isimlendirmem (bir değişkende tutmam) gerekiyordu o yüzden isimlendirdim.İlerleyen kısımlarda isimsiz closure’ları da belirtirim.

Optimizasyon konusunu ele almak için bazı fonksiyonları kullanacağım.Bu fonksiyonlar parametre olarak closure alan yapılardır yani parametre olarak fonksiyon da almaktadırlar.

Diyelim ki sınav olduk ve notlarımıza 10 puan eklenecek nasıl yaparız bunu ? Şimdi tek tek baştan bakalım.

Dizimiz ise aşağıdaki şekilde olsun

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]

Yaklaşım 1 : Diziyi for döngüsü ile gezeriz ve her elemana 10 ekleriz.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]

for (index,note) in notes.enumerated(){
notes[index] = note + 10
}
print(notes) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

pek işlevsel bir kod değil sebebi ise 10 yerine başka bir sayı gelse kodda bulmaya uğraşıcaz vs vs. O halde yaklaşımlarımızı iyileştirelim

Yaklaşım 2 : Fonksiyon oluşturalım ve bir int değerine 10 eklesin ve dizinin her elemanı için bunu uygulayalım(normalde bu şekilde yapmam closure’a geçiş yapabilmek için böyle yaklaştım)

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
func add10(_ to : Int ) -> Int {
return to + 10
}

for (index,note) in notes.enumerated(){
notes[index] = add10(note)
}
print(notes) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Yaklaşım 3 : map fonksiyonunu kullanalım.map fonksiyonu bir collection’ın her elemanı için uygulanmaktadır ve o collection’ın boyutunda ve sırasında bir collection döndürmektedir.For döngüsü ile yaptığımız işlemi map fonksiyonu ile yapacağız.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
func add10(_ to : Int ) -> Int {
return to + 10
}
var notesPlus10 = notes.map(add10)
print(notesPlus10) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Peki map fonksiyonuna add10 fonksiyonunu gönderdik şimdi ise closure gönderelim.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var closure = { (number : Int) -> Int in
return number + 10
}
var notesPlus10 = notes.map(closure)
print(notesPlus10) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Çıktı hala aynı.map fonksiyonuna ismi olan ve geriye değer döndüren bir closure gönderdik şimdi ise isimsiz bir closure gönderelim

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var notesPlus10 = notes.map({ (number : Int) -> Int in
return number + 10
})
print(notesPlus10) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Şimdi ise optimizasyonlarla kodumuzu nasıl daha kısa ve okunulur hale getiririz bakalım.

Optimizasyon 1 , parametre tiplerini ve return value tipini çıkarabiliriz (yazmayabiliriz) . “notes” dizisinin elemanlarından parametre olarak bir eleman aldığı için anlayacaktır parametre tipini. Return type’ı da kaldırabiliriz sebebi ise return ettiğimizde tür çıkarımı yapmaktadır.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var notesPlus10 = notes.map({ number in
return number + 10
})
print(notesPlus10) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Optimizasyon 2 , return etmemiz gerekiyorsa ve tek ifadeli bir closure ise return keyword’ünü kaldırabiliriz.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var notesPlus10 = notes.map({ number in
number + 10
})
print(notesPlus10) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Optimizasyon 3 , değişken adlarının kısa gösterimi. Swift satıriçi(inline) closure’lara otomatik olarak kısa argüman adlarını sağlar($0,$1,$2 … ). Eğer bu kısa argüman adlarını kullanacaksak , closure’un parametre/argüman listesinden kaldırmalıyız.Ek olarak closure tamamen gövdesinden oluşacağı için “in” keyword’ü de kaldırılmalı .Yani “number” değişkenini kaldıracak ve yerine $0 koyacağım.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var notesPlus10 = notes.map({ $0 + 10 })
print(notesPlus10) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Optimizasyon 4 , trailing closure. Eğer fonksiyonun son parametresi bir closure ise o fonksiyonun parantezleri dışına çıkarılabilir closure’umuz ve hala parametresidir.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var notesPlus10 = notes.map(){ $0 + 10 }
print(notesPlus10)// output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Devam edelim.map fonksiyonunun içinde başka bir parametre kalmadı o yüzden map fonksiyonunun parantezlerini de kaldırabiliriz.map fonksiyonu yerine başka bir fonksiyon olsaydı ve içinde başka bir parametresi olsa idi bunu yapamazdık.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var notesPlus10 = notes.map{$0 + 10}
print(notesPlus10)// output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Bu örnekte optimizasyonları baştan başlayarak tek tek yaptık ama hepsini yapmak zorunda veya aynı sıra ile yapmak zorunda değiliz. Mesela 2.optimizasyonu yapmazsak şu şekilde olurdu

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var notesPlus10 = notes.map{ return $0 + 10}
print(notesPlus10) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Mesela 2 ve 4.optimizasyonları yapmamış da olabilirdik.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var notesPlus10 = notes.map({ return $0 + 10})
print(notesPlus10) // output is [13, 71, 82, 94, 67, 48, 18, 53, 36, 91, 39]

Ek olarak 3.optimizasyonu yapabilmek için 1.optimizasyonun uygulanmış olması gerekir.

Bu optimizasyonların yararlarını göstermek için mesela sadece 4.optimizasyonla yani trailing closure kullanırsak veya kullanmazsak nasıl olur diye bakalım.Aşağıya bir projenin bir kısmından, kodu koyacağım. session.dataTask() fonksiyonuna bakarak bu trailing closure olayını anlayabilirsiniz.

func performRequest(with urlString) -> String {
// step 1 create a url
if let url = URL(string: urlString) {
// step 2 give urlSession a task
let session = URLSession(configuration: .default)
// step 3 Give urlSession a task
let task = session.dataTask(with: url, completionHandler: { (data response error) in
if error != nil {
self.delegate?.didFailWithError(error: error!)
}
if let safeData = data {
if let weather = self.parseJSON(safeData) {
self.delegate?.didUpdateWeather(self, weather : weather)
}
}
})
// step 4 start the task
task.resume()

}
}

trailing clsoure kullanmadık burada , aşağıda ise kullanalım.

    func performRequest(with urlString : String) {
// 1. Create a url
if let url = URL(string: urlString) {
// 2. Create a urlSession
let session = URLSession(configuration: .default)
// 3. Give urlSession a task
let task = session.dataTask(with: url) { data, response, error in
if error != nil {
self.delegate?.didFailWithError(error: error!)
}
if let safeData = data {
if let weather = self.parseJSON(safeData) {
self.delegate?.didUpdateWeather(self, weather : weather)
}
}
}
// 4. Start the task
task.resume()
}
}

Peki fonksiyonumuz birden fazla Closure’u parametre olarak alabilir mi ? Alırsa ne olur ?

Evet fonksiyonumuz birden fazla closure’u parametre olarak alabilir.Örnek olarak ise yukarıda bir sınav notu dizimiz vardı.Sınıf hocası bu notları alsın ve ortalamayı hesaplasın eğer 70(sayıyı attım kafadan)’den büyükse başarılı olduğunu anlar ve ona göre işlemler yapar ama değilse de başka işlemler yapar.Bunu kod üzerinde gösterelim.

Önce fonksiyonlarla halledelim.Daha sonra ise Closure’lar ile yapıp Trailing Closure’lara geçelim.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
func succeedClosure() {
print("Tebrikler sınıfınız başarılı . ")
// do something1
}
func failedClosure() {
print("Sınıfınız başarılı değil :( ")
print("Yeniden konu anlatın.")
// do something2
}
func calculateSuccessOfClass(notes : [Int],succeed : () -> Void , failed : () -> Void){
let average = Float(notes.reduce(0, +))/Float(notes.count)
if average > 70 {
succeed()
}else {
failed()
}
}
calculateSuccessOfClass(notes: notes, succeed: succeedClosure, failed: failedClosure)

Burada fonksiyonlarla yaptık.Reduce fonksiyonu ile hızlı bir şekilde toplayıp kişi sayısına bölerek ortalamayı hesapladık.Ortalamayı karşılaştırarak(if else) hangi fonksiyonun(ne yapılacağına) çalışacağına karar verdik.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
var succeedClosure = {
print("Tebrikler sınıfınız başarılı . ")
// do something1
}
var failedClosure = {
print("Sınıfınız başarılı değil :( ")
print("Yeniden konu anlatın.")
// do something2
}
func calculateSuccessOfClass(notes : [Int],succeed : () -> Void , failed : () -> Void){
let average = Float(notes.reduce(0, +))/Float(notes.count)
if average > 70 {
succeed()
}else {
failed()
}
}
calculateSuccessOfClass(notes: notes, succeed: succeedClosure, failed: failedClosure)

Burada ise Closure yapısı ile işimizi hallettik.Fonksiyon veya Closure ile yapabiliyoruz.Closure’ile yaptığımız örnekten de Closure’ların bir değişkende saklanan fonksiyonlar olduklarını anlayabilirsiniz.Şimdi ise kodumuzu Trailing Closure yapısı ile daha güzel hale getirelim.

var notes : [Int] = [3, 61, 72, 84, 57, 38, 8, 43, 26, 81, 29]
func calculateSuccessOfClass(notes : [Int],succeed : () -> Void , failed : () -> Void){
let average = Float(notes.reduce(0, +))/Float(notes.count)
if average > 70 {
succeed()
}else {
failed()
}
}
calculateSuccessOfClass(notes: notes) {
print("Tebrikler sınıfınız başarılı . ")
// do something1
} failed: {
print("Sınıfınız başarılı değil :( ")
print("Yeniden konu anlatın.")
// do something2
}

Burada gördüğünüz üzere fonksiyonu(calculateSuccessOfClass) daha güzel şekilde uyguladık zaten Closure dediğimiz yapı emre gürses ‘in de dediği gibi “Closure daha sade fonksiyon yazma sanatıdır”.

Sonuç olarak bir fonksiyon birden fazla Closure’u parametre olarak alabilir ve alıyorsa da Trailing Closure kullanarak yazmak istiyorsak : ilk Trailing Closure için argument label ı atlar geri kalan Trailing Closure’ları etiketleriz.

Escaping , Non-Escaping Closure Nedir ?

Önceden swiftte closure’lar default olarak escaping türde iken şimdi non escaping türdedir.

Default olandan başlayalım.Non-Escaping Closure’lar kullanıldıkları fonksiyon içide execute edilirler ve ramde yer kaplamaz silinirler.

Escaping Closure’lar ise kullanıldıkları fonksiyon çalıştıktan ve o fonksiyonun işi bittikten sonra çalıştırılırlar ki ram de tutabilelim ve daha sonra kullanalım.Bir closure’un escaping olduğunu belirtmek için parametre türünün önüne “@escaping ” yazarız.

Şimdi Non-Escaping olan bir closure’u fonksiyon içinde kullanalım.

func performNonEscapingOperation(completion: () -> Void) {
print("Non-Escaping Closure başlangıcı.")
completion()
print("Non-Escaping Closure bitişi.")
}
// Örnek 1: Non-Escaping Kapanış
performNonEscapingOperation {
print("Non-Escaping Closure içindeyiz")
}

Şimdi de Escaping Closure ile deneyelim.

func performEscapingOperation(completion: @escaping () -> Void) {
print("Escaping Closure başlangıcı.")
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
completion()
}
print("Escaping Closure bitişi.")
}
// Örnek 2: Escaping Kapanış
performEscapingOperation {
print("Escaping Closure içindeyiz")
}

Ekran kaydına alıp farkını görmek istedim.Escaping closure fonksiyon bittikten sonra çalışıyor 2 sn sonra ekrana yazının gelmesinden anlayabiliriz.Ekran videosu koyamadığım için gif şeklinde koydum biraz yavaş gibi gelebilir bu sebepten ötürü.

Autoclosure nedir ?

Bir “autoclosure” bir fonksiyona argüman olarak iletilen ifadeyi sarmak(wrap) için otomatik olarak oluşturulan bir closure’dır.

Açık bir şekilde closure yazmak yerine normal bir ifade yazarak bir işlevin parametresinin etrafındaki parantezleri çıkarmamıza olanak sağlar . Yani gelen parametreye “{}” süslü parantezleri ekleyerek bir closure halini almış olur.

Biz closure’u çağırmazsak/çağrısını yapmazsak o closure içinde yazan kodlar çalışmayacaktır.Bu da değerlendirmeyi geciktirmemize (delay evulation) olanak sağlar.

En son yazdığım bilgiyi desteklemesi açısından hemen bir örnek bırakıyorum aşağıya.

myFriends adında bir liste olsun ve sayısı başta gördüğünüz gibi 8.

var myFriends = ["Emirhan","İbrahim","Furkan","Galip","Talha","Samet","Eyüp","Batuhan"]
print(myFriends.count) // output is 8

Şimdi ise bir fonksiyon/closure ekleyelim.İşlevi ise myFriends dizisinin başındaki Stringi diziden kaldıracak ve geri döndürecek.

var myFriends = ["Emirhan","İbrahim","Furkan","Galip","Talha","Samet","Eyüp","Batuhan"]
print(myFriends.count)
var getNameFromMyFriends = {myFriends.remove(at: 0)}

getNameFromMyFriends bir “()->String” tipinde fonksiyondur. İnanmıyor musunuz ?

“myFriend” dizimin sayısı hala aynıdır 8. Sebebi ise daha çağırmadım “getNameFromMyFriends” closure’unu.

var myFriends = ["Emirhan","İbrahim","Furkan","Galip","Talha","Samet","Eyüp","Batuhan"]
print(myFriends.count) // output is 8
var getNameFromMyFriends = {myFriends.remove(at: 0)}
print(myFriends.count) // output is 8

Bir fonksiyon oluşturalım bize olanlar hakkında bilgi versin.

var myFriends = ["Emirhan","İbrahim","Furkan","Galip","Talha","Samet","Eyüp","Batuhan"]
print(myFriends.count) // output is 8
var getNameFromMyFriends = {myFriends.remove(at: 0)}
print(myFriends.count) // output is 8

func getInformation(from closure : () -> String) {
print("Bilgi alınıyor...")
print("Diziden gelen kişi \(closure())")
}
getInformation(from: getNameFromMyFriends) // output is : Bilgi alınıyor...
// output is : Diziden gelen kişi Emirhan
print(myFriends.count) // output is 7

Şimdi ise closure’u isimlendirmeden de kullanabiliriz zaten closure’lar fonksiyonları sade yazma sanatı idi.

var myFriends = ["Emirhan","İbrahim","Furkan","Galip","Talha","Samet","Eyüp","Batuhan"]
print(myFriends.count) // output is 8

func getInformation(from closure : () -> String) {
print("Bilgi alınıyor...")
print("Diziden gelen kişi \(closure())")
}
getInformation(from: {myFriends.remove(at: 0)}) // output is : Bilgi alınıyor...
// output is : Diziden gelen kişi Emirhan
print(myFriends.count)// output is 7

Eee biz autoclosure kullanmadık nerede kullanacağız.Şimdi autoclosure’u ekleyelim ve süslü parantezlerden kurtulalım.

var myFriends = ["Emirhan","İbrahim","Furkan","Galip","Talha","Samet","Eyüp","Batuhan"]
print(myFriends.count) // output is 8

func getInformation(from closure : @autoclosure () -> String) {
print("Bilgi alınıyor...")
print("Diziden gelen kişi \(closure())")
}
getInformation(from: myFriends.remove(at: 2)) // output is : Bilgi alınıyor...
// output is : Diziden gelen kişi Furkan
print(myFriends.count) // output is 7

Başka bir örnek vermek istiyorum.Ben bisiklet sürmeyi seven birisiyim.Bir app yaptım ve hava durumuna göre bisiklet süreceğim ve gideceğim yerler de olsun istiyorum.Bunun üzerine ve autoclosure üzerine bir şeyler denemek istiyorum şimdi.

func goWithBike(isWeatherRainy:Bool,to place : String)  {
if !isWeatherRainy {
print("I am going to \(place) with bikee")
}
}
goWithBike(isWeatherRainy: false, to: "sivas") // output is I am going to sivas with bikee

Gideceğim yeri ilk başta elim ile girerim okey ama her zaman elim ile girmek istemiyorum.Bir liste hazırlarım oradan verileri çekerim vs vs.

func getPlaceName() -> String {
print("getPlaceName function is called")
return "Bursa/Gölyazı"
}

func goWithBike(isWeatherRainy:Bool,to place : String){
if !isWeatherRainy {
print("I am going to \(place) with bikee")
}
}

goWithBike(isWeatherRainy: false, to: getPlaceName())
// output is : getPlaceName function is called
// output is : I am going to Bursa/Gölyazı with bikee

Şimdi parametreyi true yaparsam , getPlaceName fonksiyonu çalışacak bunu istemiyorum ben. Hatam ne peki ? “getPlaceName()” fonksiyonunu çalıştırıp geri dönen değeri çalıştırdım fakat hava yağmurlu olduğu için bir yere gidemedim. O

goWithBike(isWeatherRainy: true, to: getPlaceName())
// output is : getPlaceName function is called

O halde fonksiyona başka bir fonksiyonu parametre olarak geçeyim.

func getPlaceName() -> String {
print("getPlaceName function is called")
return "Bursa/Gölyazı"
}

func goWithBike(isWeatherRainy:Bool,to place : () -> String) {
if !isWeatherRainy {
print("I am going to \(place()) with bikee")
}else {
print("I am not going to anywhere because the weather is rainy.")
}
}

goWithBike(isWeatherRainy: true, to: getPlaceName) // output is : I am not going to anywhere because the weather is rainy.

Peki ben bu fonksiyona parametre olarak fonksiyon ilettiysem closure olarak da iletebilirim.Closure’u bir daha isimlendirmeye gerek yok direkt içine de yazabilirim

func goWithBike(isWeatherRainy:Bool,to place : () -> String)  {
if !isWeatherRainy {
print("I am going to \(place()) with bikee")
}else {
print("I am not going to anywhere because the weather is rainy.")
}
}

goWithBike(isWeatherRainy: false, to: { return "Bursa/Tirilye"}) // output is : I am going to Bursa/Tirilye with bikee

“return” keywordünü de kaldırabilirim.

func goWithBike(isWeatherRainy:Bool,to place : () -> String)  {
if !isWeatherRainy {
print("I am going to \(place()) with bikee")
}else {
print("I am not going to anywhere because the weather is rainy.")
}
}

goWithBike(isWeatherRainy: false, to: {"Bursa/Tirilye"}) // output is : I am going to Bursa/Tirilye with bikee

Şimdi bu closure’daki parantezler de fazla duruyor onları kaldırmak için “autoclosure” keywordünü ekleyerek duruma son noktayı koyalım.

func goWithBike(isWeatherRainy:Bool,to place : @autoclosure () -> String)  {
if !isWeatherRainy {
print("I am going to \(place()) with bikee")
}else {
print("I am not going to anywhere because the weather is rainy.")
}
}

goWithBike(isWeatherRainy: false, to: "Bursa/Tirilye") // output is : I am going to Bursa/Tirilye with bikee

Closure yazım burada bitmektedir.Bildiklerimi ve öğrendiklerimi aktarmaya çalıştım , uzun ve adım adım olmuş olabilir sebebi ise ben böyle öğreniyorum ve internette istediğim şekilde bulamadığım için böyle bir yazı neden olmasın dedim. Umarım anlatabilmişimdir.Hatalarım var ise bana developerburakgul@gmail.com mailinden ulaşabilirsiniz.Sağlıcakla ve Swiftle kalın :)

Kaynaklar

https://www.avanderlee.com/swift/autoclosure/

https://www.hackingwithswift.com/example-code/language/what-is-the-autoclosure-attribute

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures#app-top

--

--