---
title: Kapanışlar
source: 'https://academia.sh/tr/kurslar/swift/kapanislar'
course: 'Swift Dili'
language: tr
updated: '2026-10-21T05:03:11+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Kapanışı kısa sözdizimiyle, sondaki kapanış olarak yazmak'
    - 'Kapanış gövdesinin her çağrıda çalıştığını, çağrılmayan kapanışın gövdesinin hiç çalışmadığını göstermek'
    - 'Yakalama listesi ile listesiz yakalamanın farkını okumak'
---

# Kapanışlar

Kapanış sözdizimini, `$0` kısaltmasını, sondaki kapanışı ve `sorted(by:)` çağrısını tanıtır; yakalama listesinin kapanış oluşturulurken bir kez değerlendirildiğini ölçer.

Fonksiyonlar adlandırılmış davranıştır. Kapanış (closure) aynı davranışı adsız yazar ve bir değişkene koyabilir ya da başka bir fonksiyona verebilirsin. Bu dersin sorusu iki parçalı: kapanışın gövdesi ne zaman çalışır, ve kapanış çevresindeki değişkenleri hangi anda görür?

## Kapanış Yazmak

En uzun biçim, parametre ve dönüş tipini süslü parantezin içine yazar: `{ (a: Int, b: Int) -> Bool in a < b }`. `in` anahtar sözcüğü imzayı gövdeden ayırır. Tip bağlamdan çıkarılabildiğinde imza düşer ve parametrelere sıra numarasıyla erişilir: `$0` ilk, `$1` ikinci argümandır. Gövde tek bir ifadeyse `return` yazılmaz, ifadenin değeri örtük olarak döner.

Bir fonksiyonun son parametresi kapanışsa, kapanış parantezin dışına yazılabilir. Buna sondaki kapanış (trailing closure) denir. Parantez içinde başka argüman kalmadıysa parantezin kendisi de düşer: `numbers.sorted { $0 > $1 }`. `sorted(by:)` bir diziyi verdiğin karşılaştırma kapanışına göre sıralar.

```swift
// Probe.swift — bir ifadenin ne zaman degerlendirildigini kaydeder
final class Probe {
    let label: String
    private(set) var evaluations = 0
    private(set) var uses = 0
    private var evaluatedBeforeUse = false

    init(_ label: String) {
        self.label = label
    }

    func eval<T>(_ value: T) -> T {
        evaluations += 1
        if uses == 0 { evaluatedBeforeUse = true }
        return value
    }

    func use<T>(_ access: () -> T) -> T {
        uses += 1
        return access()
    }

    var moment: String {
        if evaluations == 0 { return "hic" }
        if evaluations > 1 { return "her-kullanimda" }
        return evaluatedBeforeUse ? "hemen" : "ilk-kullanimda"
    }

    func report() {
        print("\(label): \(evaluations) degerlendirme, \(uses) kullanim -> \(moment)")
    }
}

func tally(_ probes: [Probe]) {
    for moment in ["hemen", "ilk-kullanimda", "her-kullanimda", "hic"] {
        let count = probes.filter { $0.moment == moment }.count
        print("\(moment): \(count)")
    }
}
```

Ölçüm bloğu önce bu biçimleri çalıştırır: uzun kapanış, `$0` ile kısa kapanış, `map` ve kendi yazdığımız `apply`. Ardından iki kapanış kurar. `scale` gövdesinde bir `Probe` taşır ve iki kez çağrılır; `unused` aynı biçimde kurulur ama hiç çağrılmaz.

```swift
// main.swift — kapanis bicimleri ve govde ani
let numbers = [3, 1, 2]
print(numbers.sorted(by: { (a: Int, b: Int) -> Bool in a < b }))
print(numbers.sorted { $0 > $1 })
print(numbers.map { $0 * 2 })

func apply(_ n: Int, using transform: (Int) -> Int) -> Int { transform(n) }
print(apply(4) { $0 + 1 })

let bodyProbe = Probe("kapanis-govdesi")
let unusedProbe = Probe("cagrilmayan-govde")

let scale = { (n: Int) -> Int in bodyProbe.eval(n * 2) }
let unused = { (n: Int) -> Int in unusedProbe.eval(n) }

print(bodyProbe.use { scale(1) })
print(bodyProbe.use { scale(2) })
_ = unusedProbe.use { unused }
_ = unusedProbe.use { unused }

let allProbes = [bodyProbe, unusedProbe]
for probe in allProbes { probe.report() }
tally(allProbes)
```

```
[1, 2, 3]
[3, 2, 1]
[6, 2, 4]
5
2
4
kapanis-govdesi: 2 degerlendirme, 2 kullanim -> her-kullanimda
cagrilmayan-govde: 0 degerlendirme, 2 kullanim -> hic
hemen: 0
ilk-kullanimda: 0
her-kullanimda: 1
hic: 1
```

`sorted(by:)` sonucu küçükten büyüğe, `$0 > $1` ile büyükten küçüğe verdi. `map` her elemanı ikiye katladı ve `apply(4)` sondaki kapanışla 5 döndü. Ölçüm satırları kapanışın gövdesine bakar: `kapanis-govdesi` iki çağrıda iki kez değerlendirildi, yani gövde her çağrıda yeniden çalışır ve an `her-kullanimda` olur. `cagrilmayan-govde` ise iki kullanımda sıfır değerlendirme gösterdi: kapanışı kurmak gövdeyi çalıştırmaz, gövde yalnız çağrı olduğunda çalışır.

**DT53.** `sorted(by:)` karşılaştırma kapanışının kaç kez çağrıldığı bu derste sayılmadı; sayı sıralama algoritmasına bağlıdır ve ders yalnız sonucu gösterir.

**DT54.** Kapanış gövdesi yalnız `Int` döndüren, yan etkisi olmayan basit bir ifadeyle ölçüldü; kaçan (escaping) kapanışlar bu dersin dışındadır.

## Kaçan Kapanış: Saklanan İş

Bir kapanışı fonksiyona verirsen ve fonksiyon kapanışı kendi bitişinden sonra da saklarsa, kapanışın tipi `@escaping` ile işaretlenmelidir. Bu işaret, kapanışın çağrıdan kaçabileceğini söyler. Kaçmayan kapanış (varsayılan) çağrı bitince ortadan kalkar. Kaçan kapanış ise bir diziye eklenebilir, bir özelliğe atanabilir ve sonra çağrılabilir. Kapanışı kuran satır işi yapmaz; işi, kapanış çağrıldığında yapılır.

Aşağıdaki blok bir kuyruk sınıfı yazar. `add` kapanışı saklar, `runAll` saklananların hepsini çağırır. Kapanışın gövdesi bir `Probe`'a yazar. Kapanışlar kuyruğa eklendikten sonra ve çalıştırıldıktan sonra değerlendirme sayısı yazdırılır.

```swift
// Queue.swift — saklanan kapanis
final class Queue {
    var jobs: [() -> Int] = []
    func add(_ job: @escaping () -> Int) {
        jobs.append(job)
    }
    func runAll() {
        for job in jobs { _ = job() }
    }
}
let queueProbe = Probe("saklanan-is")
let queue = Queue()
queue.add { queueProbe.eval(1) }
queue.add { queueProbe.eval(2) }
print(queueProbe.evaluations)
_ = queueProbe.use { queue.runAll() }
_ = queueProbe.use { queue.runAll() }
print(queueProbe.evaluations)
queueProbe.report()
```

```
0
4
saklanan-is: 4 degerlendirme, 2 kullanim -> her-kullanimda
```

İki kapanış kuyruğa eklendiğinde sayaç 0'dı: ekleme gövdeyi çalıştırmadı. İki `runAll` çağrısından sonra sayaç 4 oldu, çünkü her çağrıda iki kapanış çalıştı. Kapanışlar saklandı ve her çağrıldığında gövdeyi yeniden değerlendirdi; bu yüzden an `her-kullanimda` okunur.

Kaçan kapanış, işi ertelemenin yoludur. Gövdenin ne zaman çalışacağını kapanışı kuran satırdan değil, onu çağıran satırdan okursun.

**DT55.** Saklanan kapanışlar bir sınıf içinde ölçüldü; kaçan kapanışta `self` yakalamanın sonuçları bu dersin dışındadır.

## Kısaltılmış Argüman Adları

Kapanış parametrelerine `$0`, `$1` gibi adlar verebilirsin. Bu, tip bağlamdan çıkarıldığında parametre listesini yazmaktan kurtarır. Gövde tek bir ifadeyse örtük dönüş de çalışır. Standart kütüphane işleçleri de bir fonksiyon gibi geçilebilir: `numbers.sorted(by: >)` yazmak `numbers.sorted { $0 > $1 }` ile aynı işi yapar. `reduce` iki parametreli bir kapanış alır ve bu parametreler `$0` ve `$1` olur.

Aşağıdaki blok bir dizi üzerinde üç kısaltılmış biçimi çalıştırır. `map` her elemanı bir `Probe`'dan geçirir ve ikinci bir `map` çağrısı bu kez dört elemana uygulanır.

```swift
// Shorthand.swift — kisaltilmis argumanlar
let mapProbe = Probe("map-govdesi")
let numbers = [3, 1, 2]
print(numbers.sorted(by: >))
print(numbers.reduce(0) { $0 + $1 })
print(mapProbe.use { numbers.map { mapProbe.eval($0 * 10) } })
print(mapProbe.use { (numbers + [4]).map { mapProbe.eval($0 * 10) } })
mapProbe.report()
```

```
[3, 2, 1]
6
[30, 10, 20]
[30, 10, 20, 40]
map-govdesi: 7 degerlendirme, 2 kullanim -> her-kullanimda
```

`sorted(by: >)` `[3, 2, 1]` verdi. `reduce` toplamı 6 olarak hesapladı. İki `map` çağrısı `[30, 10, 20]` ve `[30, 10, 20, 40]` dizilerini üretti. `Probe` yedi değerlendirme gösterdi: ilk çağrıda üç, ikincisinde dört. Kapanış gövdesi her eleman için bir kez çalıştı. Bu yüzden an `her-kullanimda` okunur.

Kısaltılmış adlar gövde kısa olduğunda okunur; gövde uzadığında adlandırılmış parametre anlamı korur. `$0` ve `$1` yanında işleci doğrudan geçmek en kısa yazımdır ama yalnız işlecin imzası kapanışın imzasıyla eşleştiğinde çalışır.

**DT56.** Kısaltılmış adlar `Int` dizisiyle ölçüldü; `$2` ve sonrası ile iç içe kapanışlarda `$0` anlamı bu dersin dışındadır.

## Kapanış Yakaladığı Değişkeni Değiştirebilir

Yakalanan değişken bir `var` ise kapanış onu yalnız okumakla kalmaz, değiştirebilir de. Kapanış değişkenin bir kopyasını değil, kendisini tutar. Aynı değişkeni birden çok kapanış yakalarsa, bir kapanışın yaptığı değişiklik diğerinin gördüğü değeri değiştirir. Bu yüzden yakalanan `var`'lar paylaşılan durum gibi davranır ve değişkenin ömrü, onu yakalayan kapanışlarla birlikte uzar.

Aşağıdaki blok bir `hits` sayacını iki kapanışla yakalar. `record` sayacı bir artırır ve değeri bir `Probe`'dan geçirir; `skip` sayacı doğrudan iki artırır. Kapanışlar sırayla `record`, `skip`, `record` biçiminde çağrılır.

```swift
// Shared.swift — ortak yakalanan degisken
let sharedProbe = Probe("ortak-sayac")
var hits = 0
let record = {
    hits += 1
    return sharedProbe.eval(hits)
}
let skip = { hits += 2 }
print(sharedProbe.use { record() })
skip()
print(sharedProbe.use { record() })
print(hits)
sharedProbe.report()
```

```
1
4
4
ortak-sayac: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

`record` ilk çağrıda 1, `skip` sayacı 3 yaptıktan sonra ikinci çağrıda 4 döndürdü; son okuma `hits` değerinin 4 olduğunu doğruladı. İki kapanış aynı değişkeni gördü: `record`, `skip`'in yaptığı değişikliği ikinci çağrıda gördü. İki çağrı iki değerlendirme getirdi ve an `her-kullanimda` olur.

Paylaşılan durum esneklik sağlar, ama hangi kapanışın değişkeni ne zaman değiştirdiğini izlemeyi zorlaştırır. Durum küçük ve yakın olduğunda sorun olmaz; büyüdükçe durumu bir tipin içine almak daha okunur olur.

**DT57.** Paylaşılan durum bir `Int` üzerinde ölçüldü; eşzamanlı çalışan kapanışların aynı değişkene erişmesi bu dersin dışındadır.

## Sondaki Kapanış Söz Dizimi

Bir fonksiyonun son parametresi kapanışsa, kapanışı parantezlerin dışına yazabilirsin. `perform(times: 2) { ... }` ile `perform(times: 2, action: { ... })` aynı çağrıdır. Fonksiyonun tek argümanı kapanışsa, parantezler tümüyle kalkabilir. Bu söz dizimi yalnız yazımı kısaltır; kapanışın ne zaman çalıştığı değişmez. Kapanış, fonksiyon onu çağırdığında çalışır ve kaç kez çağırırsa o kadar kez çalışır.

Aşağıdaki blok bir fonksiyon yazar: `perform` verilen kapanışı istenen sayıda çağırır. Kapanış gövdesi bir `Probe`'a yazar. Fonksiyon önce iki, sonra üç tekrarla çağrılır.

```swift
// Trailing.swift — sondaki kapanis
func perform(times: Int, action: () -> Void) {
    for _ in 0..<times { action() }
}
let trailingProbe = Probe("sondaki-kapanis")
trailingProbe.use { perform(times: 2) { _ = trailingProbe.eval(1) } }
trailingProbe.use { perform(times: 3) { _ = trailingProbe.eval(1) } }
print(trailingProbe.evaluations)
trailingProbe.report()
```

```
5
sondaki-kapanis: 5 degerlendirme, 2 kullanim -> her-kullanimda
```

`perform(times: 2)` iki, `perform(times: 3)` üç kez çalıştırdı; toplam beş değerlendirme çıktı. Kapanışı parantezin dışına yazmak çalışma sayısını değiştirmedi: `times` değeri, kapanışın kaç kez çağrılacağını belirledi. Her çağrıda gövde yeniden değerlendirildi ve an `her-kullanimda` okunur.

Bu söz dizimi yalnız okunuşa yardım eder. Kapanış parametreler arasında son sıradaysa, çağrı bir kontrol akışı ifadesine benzer: `perform(times: 3) { ... }` bir döngü gibi okunur. Ama arkasındaki kural aynıdır: kapanış bir değerdir ve fonksiyon onu istediği kadar çağırır.

**DT58.** Sondaki kapanış dönüş değeri olmayan bir kapanışla ölçüldü; birden çok sondaki kapanışın söz dizimi bu dersin dışındadır.

## Yakalama Listesi Değeri Dondurur

Bir kapanış, çevresindeki bir `var` değişkeni yakaladığında değişkenin kendisini tutar; sonradan değişkende yapılan değişiklikler kapanışa yansır. Bunu değiştirmek istersen kapanışın başına bir yakalama listesi yazarsın: `{ [snapshot = count] in snapshot }`. Liste, kapanış oluşturulduğu anda `count` değerinin bir kopyasını alır ve kapanış artık onu kullanır. Sonradan `count` değişse bile kapanışın gördüğü sayı aynı kalır.

Aşağıdaki blok aynı değişkeni iki kapanışla yakalar: biri liste kullanmaz, biri kullanır. Kapanışlar oluşturulduktan sonra değişken değiştirilir ve ikisi de çağrılır. Okunan değer bir `Probe` üzerinden geçer.

```swift
// CaptureList.swift — yakalama listesi
let listProbe = Probe("yakalama-listesi")
var count = 1
let live = { listProbe.eval(count) }
let frozen = { [snapshot = count] in listProbe.eval(snapshot) }
count = 5
print(listProbe.use { live() }, listProbe.use { frozen() })
listProbe.report()
```

```
5 1
yakalama-listesi: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

`live` kapanışı `5`, `frozen` kapanışı `1` verdi. `live` değişkenin kendisini tuttuğu için `count = 5` atamasından sonra yeni değeri gördü. `frozen` ise oluşturulduğu anda `count` değerinin bir kopyasını `snapshot` adıyla aldı; sonradan değişkeni değiştirmek ona ulaşmadı. İki çağrı iki değerlendirme getirdi ve an `her-kullanimda` olur.

Yakalama listesi, kapanışın hangi değeri göreceğini açıkça yazmanın yoludur. Bir değerin kapanış oluştuğu andaki hâliyle kalmasını istiyorsan listeye yazarsın; değişkenin sonradan alacağı değerleri görmesini istiyorsan listeyi hiç kullanmazsın.

Yakalama listesine birden çok kalem de yazabilirsin; her kalem, kapanış oluştuğu anda kendi kopyasını alır.

**DT59.** Yakalama listesi bir `Int` değişkenle ölçüldü; sınıf örneklerini zayıf yakalama bu dersin dışındadır ve sonraki konuda ele alınır.

## Sınırlayıcı Ölçüm

Kapanış çevresindeki bir değişkeni kullanıyorsa onu yakalar (capture). Listesiz yakalamada kapanış değişkenin kendisine bağlanır: değişken sonradan değişirse kapanış her çağrıda yeni değeri görür. Yakalama listesi (capture list) ise köşeli parantez içinde yazılır ve kapanış oluşturulurken bir değer alır: `{ [snapshot = level] in snapshot }`. Listedeki ifade kapanış kurulurken bir kez değerlendirilir, çağrılarda yeniden değerlendirilmez. Aşağıdaki ölçüm iki kapanışı aynı değişkenle kurar, değişkeni değiştirir ve ikisini de iki kez çağırır.

```swift
// main.swift — yakalama listesi
let captureProbe = Probe("yakalama-listesi")

var level = 1
let plain = { level }
let listed = { [snapshot = captureProbe.eval(level)] in snapshot }
level = 5

print(captureProbe.use { plain() }, captureProbe.use { listed() })
print(captureProbe.use { plain() }, captureProbe.use { listed() })

let allProbes = [captureProbe]
for probe in allProbes { probe.report() }
tally(allProbes)
```

```
5 1
5 1
yakalama-listesi: 1 degerlendirme, 4 kullanim -> hemen
hemen: 1
ilk-kullanimda: 0
her-kullanimda: 0
hic: 0
```

`plain` kapanışı `level` değişkenine bağlı kaldığı için 5 gördü; `listed` kapanışı kurulduğu andaki 1 değerini taşıdı. Yakalama listesindeki ifade, kapanış kurulurken ve dört kullanımdan önce bir kez değerlendirildi: `yakalama-listesi` satırı `hemen` verir. Gövdenin her çağrıda çalışması ile yakalama listesinin bir kez çalışması aynı kapanışın iki ayrı anıdır.

**DT60.** `level` bir `var`'dır ve ölçüm yalnız değer tipi bir değişkenin yakalanmasını gösterir; sınıf örneklerinin yakalanması bu derste ölçülmedi.

**DT61.** Yakalama listesinin kapanış kurulurken bir kez çalışması tek bir kapanışla ölçüldü; aynı kapanışı birden çok yerde kuran kodlarda her kuruluşun ayrı bir değerlendirme olduğu bu dersin dışındadır.

## Özet

- Kapanış, adsız bir davranıştır; `$0` ve `$1` argümanlara sıra numarasıyla erişir, tek ifadelik gövde `return` gerektirmez.
- Son parametre kapanışsa, kapanış parantezin dışına yazılabilir (sondaki kapanış).
- Kapanış gövdesi her çağrıda çalışır; hiç çağrılmayan kapanışın gövdesi hiç çalışmaz.
- Yakalama listesi kapanış kurulurken bir kez değerlendirilir; listesiz yakalanan değişkenin sonradan değişmesi çağrıda görünür.
- Bu dersin anı: **her kullanımda** (kapanış gövdesi).

## Sonraki Adım

Bu konudaki örnekler `values.min() ?? 0` gibi bir ifade kullandı: `min()` boş bir dizi için değer döndüremez. Swift bu durumu bir değerin yokluğu olarak tipte taşır. Bir sonraki konunun ilk dersi, İsteğe Bağlı Değerler, bu fikri tanıtıyor.
