---
title: 'Denetim Akışı'
source: 'https://academia.sh/tr/kurslar/swift/denetim-akisi'
course: 'Swift Dili'
language: tr
updated: '2026-10-21T05:03:11+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - '`if` / `else if` zincirini ve `switch` içindeki desen eşlemeyi kullanmak'
    - 'İlk eşleşmeden sonraki koşulların değerlendirilmediğini göstermek'
    - '`for ... where` ve `while` koşullarının kaç kez değerlendirildiğini okumak'
    - '`switch` ifadesinin tümlük şartını açıklamak'
---

# Denetim Akışı

Koşulları, döngüleri ve desen eşlemeli `switch` ifadesini tanıtır; ilk eşleşmeden sonraki `where` koşullarının hiç değerlendirilmediğini ölçer.

İşleçler iki ifadeyi birleştirdi ve sağ taraf gerekmediğinde hiç değerlendirilmedi. Denetim akışı aynı fikri bir adım yukarı taşır: hangi dalın çalışacağına koşullar karar verir ve ilk uygun dalı bulan yapı geri kalanına bakmaz. Bu dersin sorusu şu: bir zincirde, eşleşmeden sonra gelen koşullar ne zaman değerlendiriliyor?

## Koşullar, Döngüler ve switch

`if` bir `Bool` koşulu sorar; `else if` zinciri koşulları yukarıdan aşağı dener. `for n in 1...3` bir aralıktaki her değer için gövdeyi çalıştırır, `while` koşul doğru olduğu sürece sürer. `switch` ise bir değeri desenlerle (pattern) karşılaştırır. Bir `case` bir değer, bir aralık, bir demet ya da `where` ile süslenmiş bir koşul olabilir. Swift'te `case` gövdeleri bir sonrakine düşmez; ilk eşleşen çalışır ve `switch` biter.

`switch` tükenmeli olmak zorundadır: her olası değer bir `case` tarafından karşılanmalı ya da bir `default` bulunmalıdır. Aşağıdaki parça `Int` için yalnız 1 ve 2'yi ele alır. Bu parça Swift 6.4'te derlenmez; derleyici onu reddeder, bu yüzden çıktısızdır.

```swift
let n = 3
switch n {
case 1: print("bir")
case 2: print("iki")
}
```

Hata gerçek bir güvencedir: yeni bir değer eklendiğinde karşılanmayan `switch` derlenmez. Çözüm `default` eklemek ya da kalan değerleri bir desenle yakalamaktır.

```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 iki zincir kurar. İlkinde `grade` fonksiyonu 75 puanı değerlendirir: ilk koşul yanlış, ikincisi doğrudur ve üçüncüsüne hiç gelinmez. İkincisinde `describe` fonksiyonu `-5` değerini bir `switch` ile sınar: ilk `case`'in `where` koşulu doğrudur, sonraki `case`'in `where` koşulu hiç sorulmaz.

```swift
// main.swift — zincirde ilk eslesmeden sonrasi
func grade(_ score: Int, _ second: Probe, _ third: Probe) -> String {
    if score >= 90 {
        return "A"
    } else if second.eval(score >= 70) {
        return "B"
    } else if third.eval(score >= 50) {
        return "C"
    }
    return "F"
}

func describe(_ n: Int, _ first: Probe, _ later: Probe) -> String {
    switch n {
    case let x where first.eval(x < 0):
        return "negatif"
    case let x where later.eval(x > 100):
        return "buyuk"
    default:
        return "diger"
    }
}

for n in 1...3 { print("adim", n) }

let secondProbe = Probe("else-if-ikinci-kosul")
let thirdProbe = Probe("else-if-ucuncu-kosul")
let firstWhereProbe = Probe("switch-ilk-where")
let laterWhereProbe = Probe("switch-sonraki-where")

for _ in 1...2 {
    let letter = secondProbe.use { thirdProbe.use { grade(75, secondProbe, thirdProbe) } }
    print(letter)
    let kind = firstWhereProbe.use { laterWhereProbe.use { describe(-5, firstWhereProbe, laterWhereProbe) } }
    print(kind)
}

let allProbes = [secondProbe, thirdProbe, firstWhereProbe, laterWhereProbe]
for probe in allProbes { probe.report() }
tally(allProbes)
```

```
adim 1
adim 2
adim 3
B
negatif
B
negatif
else-if-ikinci-kosul: 2 degerlendirme, 2 kullanim -> her-kullanimda
else-if-ucuncu-kosul: 0 degerlendirme, 2 kullanim -> hic
switch-ilk-where: 2 degerlendirme, 2 kullanim -> her-kullanimda
switch-sonraki-where: 0 degerlendirme, 2 kullanim -> hic
hemen: 0
ilk-kullanimda: 0
her-kullanimda: 2
hic: 2
```

`else-if-ikinci-kosul` her çağrıda değerlendirildi, çünkü birinci koşul yanlış olduğu için zincir ona geldi. `else-if-ucuncu-kosul` ise iki çağrıda da `hic` çıktı: ikinci koşul zaten doğruydu ve zincir orada bitti. Aynı şey `switch` için de geçerli: ilk `where` her seferinde sınandı, sonraki `where` hiç sınanmadı. Yani `where` koşulundaki bir yan etki, daha önceki bir `case` eşleştiyse hiç gerçekleşmez.

**DT39.** Ölçüm tek bir giriş değeriyle (75 ve -5) yapıldı; başka girişlerde hangi koşulun `hic` kalacağı değişir.

**DT40.** `switch`'in kaynak sırasıyla yukarıdan aşağı denendiği ölçümden çıkarıldı; derleyicinin sırayı değiştirip değiştirmediği ayrıca ölçülmedi.

## guard ile Erken Çıkış

`guard` bir koşulu doğrulamaya yarar ve koşul sağlanmazsa kapsamdan çıkmayı zorunlu kılar. Söz dizimi `guard koşul else { çıkış }` biçimindedir; `else` bloğu `return`, `break`, `continue` ya da bir durduran çağrıyla bitmek zorundadır. Koşul sağlanırsa kontrol `guard` satırının ardından devam eder ve koşulda bağlanan adlar o kapsamın geri kalanında görünür. `if` ile aynı işi görür, ama niyeti tersine çevirir: önce istenmeyen durum elenir, sonra asıl iş düz bir yolda yazılır.

Aşağıdaki blok pozitif sayıyı kabul eden bir fonksiyon yazar. Geçerli yol bir `Probe`'a, geçersiz yol başka bir `Probe`'a yazar. Fonksiyon üç sayıyla çağrılır ve her çağrıdan önce iki `Probe` birer kullanım kaydeder.

```swift
// Guard.swift — guard ile erken cikis
func check(_ number: Int, valid: Probe, invalid: Probe) -> String {
    guard number > 0 else { return invalid.eval("gecersiz") }
    return valid.eval("gecerli")
}
func observe<T>(_ watched: [Probe], _ work: () -> T) -> T {
    for probe in watched { _ = probe.use { 0 } }
    return work()
}
let validProbe = Probe("gecerli-yol")
let invalidProbe = Probe("gecersiz-yol")
for number in [5, -2, 7] {
    print(observe([validProbe, invalidProbe]) {
        check(number, valid: validProbe, invalid: invalidProbe)
    })
}
validProbe.report()
invalidProbe.report()
```

```
gecerli
gecersiz
gecerli
gecerli-yol: 2 degerlendirme, 3 kullanim -> her-kullanimda
gecersiz-yol: 1 degerlendirme, 3 kullanim -> ilk-kullanimda
```

Üç sayı `gecerli`, `gecersiz`, `gecerli` sonuçlarını verdi. Geçerli yol iki kez, geçersiz yol bir kez çalıştı: `gecerli-yol` iki değerlendirme ve üç kullanımla `her-kullanimda`, `gecersiz-yol` ise bir değerlendirme ve üç kullanımla `ilk-kullanimda` çıktı. Kullanım sayısı üç çıktı, çünkü `observe` her çağrıdan önce kullanımı kaydetti. Bir yolun ürettiği ifade, yalnız o yol seçildiğinde değerlendirilir; seçilmeyen yolun ifadesi hiç çalışmaz.

`guard`, hangi yolun hangi anda çalıştığını okunur kılar: istisna yolu en başta durur ve geride kalan satırlar yalnız koşul sağlandığında çalışır. Ölçüm bu okunuşu doğruluyor.

**DT41.** `guard` yalnız bir tam sayı koşuluyla ölçüldü; isteğe bağlı değerlerle `guard let` kullanımı sonraki konunun işidir.

## switch Desenleri

`switch` ifadesi bir değeri sırayla desenlerle karşılaştırır. Desenler yalnız değişmez olmak zorunda değildir: demet desenleri birden çok değeri aynı anda karşılaştırır, `let` ile değer bağlanır ve `where` bir koşul ekler. Örneğin `case (let x, 0)` ikinci elemanı sıfır olan her demeti yakalar ve ilk elemanı `x` adına bağlar. Eşleşen ilk durum çalışır ve diğerleri hiç değerlendirilmez.

Aşağıdaki blok bir noktanın sınıfını bulan bir fonksiyon yazar. Üç durumun her biri kendi `Probe`'una yazar. Fonksiyon üç noktayla çağrılır: orijin iki kez, yatay eksendeki bir nokta bir kez; üçüncü durum hiç eşleşmez.

```swift
// Pattern.swift — switch desenleri
func classify(_ x: Int, _ y: Int, watched: [Probe]) -> String {
    switch (x, y) {
    case (0, 0):
        return watched[0].eval("orijin")
    case (let along, 0):
        return watched[1].eval("yatay \(along)")
    case (_, let height) where height > 5:
        return watched[2].eval("yuksek \(height)")
    default:
        return "diger"
    }
}
func observe<T>(_ watched: [Probe], _ work: () -> T) -> T {
    for probe in watched { _ = probe.use { 0 } }
    return work()
}
let originProbe = Probe("orijin-durumu")
let axisProbe = Probe("eksen-durumu")
let highProbe = Probe("yuksek-durum")
let cases = [originProbe, axisProbe, highProbe]
for point in [(0, 0), (4, 0), (0, 0)] {
    print(observe(cases) { classify(point.0, point.1, watched: cases) })
}
for probe in cases { probe.report() }
```

```
orijin
yatay 4
orijin
orijin-durumu: 2 degerlendirme, 3 kullanim -> her-kullanimda
eksen-durumu: 1 degerlendirme, 3 kullanim -> ilk-kullanimda
yuksek-durum: 0 degerlendirme, 3 kullanim -> hic
```

Üç çağrı `orijin`, `yatay 4`, `orijin` sonuçlarını verdi. `orijin-durumu` iki değerlendirmeyle `her-kullanimda`, `eksen-durumu` tek değerlendirmeyle `ilk-kullanimda`, `yuksek-durum` ise sıfır değerlendirmeyle `hic` çıktı. Üçüncü durum `where` koşuluna rağmen hiç denenmedi, çünkü önceki iki durum noktaları zaten yakalamıştı. Yani `switch` sırayla bakar, ilk eşleşmeyi alır ve gerisine dokunmaz.

Bu kural desenleri sıralarken önem taşır: genel bir durumu özel bir durumdan önce yazarsan özel durum hiç çalışmaz. Derleyici kapsam eksikliğini hata olarak reddeder, ama sıra yanlışlığını bazı durumlarda bulamaz.

**DT42.** Desenler demet ve `where` ile ölçüldü; numaralandırma durumları ve aralık desenleri bu dersin dışındadır.

## Etiketli Deyimler

İç içe döngülerde `break` yalnız en içteki döngüyü bitirir. Dış döngüyü bitirmek için döngüye bir etiket verirsin: `outer: for row in 1...3 { ... }`. İçerideki `break outer` bu etikete atlar ve dış döngü biter. `continue` de aynı etiketle dış döngünün bir sonraki yinelemesine geçer. Etiket, hangi döngüden söz ettiğini açıkça yazmanın yoludur.

Aşağıdaki blok çarpım tablosunda belirli bir çarpımı arayan bir fonksiyon yazar. Her çarpım bir `Probe` üzerinden hesaplanır; böylece dönülen yineleme sayısı ölçülür. Fonksiyon iki hedefle çağrılır.

```swift
// Label.swift — etiketli break ile arama
func search(target: Int, probe: Probe) -> String {
    var found = "yok"
    outer: for row in 1...3 {
        for col in 1...3 {
            if probe.eval(row * col) == target {
                found = "\(row)x\(col)"
                break outer
            }
        }
    }
    return found
}
let searchProbe = Probe("carpim-aramasi")
print(searchProbe.use { search(target: 4, probe: searchProbe) })
print(searchProbe.use { search(target: 6, probe: searchProbe) })
searchProbe.report()
```

```
2x2
2x3
carpim-aramasi: 11 degerlendirme, 2 kullanim -> her-kullanimda
```

İlk arama `2x2`, ikincisi `2x3` buldu. Toplam on bir değerlendirme gerekti: ilk aramada beş çarpım hesaplandı (1, 2, 3, 2, 4), ikincisinde altı (1, 2, 3, 2, 4, 6). `break outer` bulunur bulunmaz iki döngüyü birden bitirdi, bu yüzden kalan çarpımlar hiç hesaplanmadı. Etiketsiz `break` yalnız iç döngüyü bitirirdi ve dış döngü bir sonraki satırla devam ederdi. An `her-kullanimda` okunur.

Etiketli çıkış, aramayı gereksiz çarpımlardan korur. Etiket kodun kaç döngü atladığını da gösterir; okuyan hangi döngünün bittiğini adından bilir.

**DT43.** Etiketli `break` iki iç içe döngüyle ölçüldü; `continue` ile etiket kullanımı bu dersin dışındadır.

## repeat-while ile En Az Bir Tur

`while` döngüsü koşulu önce denetler; koşul baştan yanlışsa gövde hiç çalışmaz. `repeat-while` bunu tersine çevirir: gövde önce çalışır, koşul sonra denetlenir. Böylece gövde, koşul ne olursa olsun, en az bir kez çalışır. Bir değeri en az bir kez okumak ya da bir işlemi bir kez yapıp sonra devam edip etmeyeceğine karar vermek gerektiğinde bu biçim doğru araçtır.

Aşağıdaki blok iki döngüyü aynı baştan yanlış koşulla çalıştırır. Her gövde bir sayaca değerini bir `Probe`'dan gelen bir ile artırır. Biri `while`, öbürü `repeat-while` ile yazılmıştır.

```swift
// Repeat.swift — repeat-while en az bir tur
let whileProbe = Probe("while-govdesi")
let repeatProbe = Probe("repeat-govdesi")
var whileCount = 0
var repeatCount = 0
_ = whileProbe.use {
    while whileCount < 0 { whileCount += whileProbe.eval(1) }
}
_ = repeatProbe.use {
    repeat { repeatCount += repeatProbe.eval(1) } while repeatCount < 0
}
print(whileCount, repeatCount)
whileProbe.report()
repeatProbe.report()
```

```
0 1
while-govdesi: 0 degerlendirme, 1 kullanim -> hic
repeat-govdesi: 1 degerlendirme, 1 kullanim -> ilk-kullanimda
```

Aynı baştan yanlış koşulla iki döngü `0 1` verdi: `while` sayacı hiç artırmadı, `repeat-while` bir kez artırdı. `while-govdesi` sıfır değerlendirmeyle `hic`, `repeat-govdesi` ise bir değerlendirmeyle `ilk-kullanimda` çıktı. `repeat-while` döngüsünde koşul gövdeden sonra denetlendiği için gövdenin ifadesi, koşul yanlış olsa bile bir kez çalıştı.

Seçim sorusu şudur: gövde, koşuldan önce en az bir kez çalışmak zorunda mı? Bir değeri okuyup sonra karar veriyorsan `repeat-while`, koşul baştan sağlanmıyorsa hiçbir şey yapmak istemiyorsan `while` doğru araçtır.

**DT44.** `repeat-while` baştan yanlış bir koşulla ölçüldü; koşulun doğru kaldığı döngülerde iki biçimin aynı sonucu verdiği bu dersin dışındadır.

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

Zincirdeki koşullar bir kez sorulup bırakılırdı. Döngülerde koşul her turda yeniden sorulur. `for ... where` her yinelemede koşulu değerlendirir; yani `where` içindeki ifade bu satırda `her-kullanimda` olur. `while` ise bir ince ayrıntı taşır: koşul, döngüden çıkarken de bir kez daha değerlendirilir, çünkü döngüden çıkmanın tek yolu koşulun `false` dönmesidir. Üç tur süren bir `while` bu yüzden koşulu dört kez değerlendirir.

```swift
// main.swift — dongu kosullari
let whereProbe = Probe("for-where-kosulu")
let whileProbe = Probe("while-kosulu")

for _ in 1...2 {
    var evens: [Int] = []
    whereProbe.use {
        for n in 1...4 where whereProbe.eval(n % 2 == 0) { evens.append(n) }
    }
    print(evens)
    whileProbe.use {
        var i = 0
        while whileProbe.eval(i < 3) { i += 1 }
    }
}

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

```
[2, 4]
[2, 4]
for-where-kosulu: 8 degerlendirme, 2 kullanim -> her-kullanimda
while-kosulu: 8 degerlendirme, 2 kullanim -> her-kullanimda
hemen: 0
ilk-kullanimda: 0
her-kullanimda: 2
hic: 0
```

İki tur boyunca `for ... where` koşulu sekiz kez, her tur dört yineleme için birer kez değerlendirildi. `while` koşulu ise iki turun her birinde üç yineleme yaptığı hâlde sekiz değerlendirme aldı: yineleme sayısı artı bir. Fazladan olan değerlendirme, döngüyü bitiren `false` sorgusudur.

**DT45.** `while` için "yineleme artı bir" sonucu bu üç yinelemelik örnekte ölçüldü; `break` ya da `return` ile çıkan bir döngüde ek sorgu yoktur, ancak bu derste ölçülmedi.

## Özet

- `if` / `else if` zinciri koşulları yukarıdan aşağı dener ve ilk doğruda durur.
- `switch` tükenmelidir; eksik `case` derleyicide reddedilir.
- İlk eşleşmeden sonraki `where` koşulları ve `else if` koşulları hiç değerlendirilmez.
- `for ... where` koşulu her yinelemede, `while` koşulu yineleme sayısından bir fazla değerlendirilir.
- Bu dersin anı: **hiç** (eşleşmeden sonraki `where`).

## Sonraki Adım

Bir koşul yalnız bir dalın çalışıp çalışmayacağını söyler. Bir de çağrı sırasında ne zaman değerlendirildiği sorulan ifadeler var: fonksiyonun varsayılan argümanı. Sıradaki ders, argüman etiketlerini ve varsayılan değerleri ölçüyor.
