---
title: Bağlama
source: 'https://academia.sh/tr/kurslar/swiftui/baglama'
course: 'SwiftUI ile Arayüz'
language: tr
updated: '2026-10-21T05:03:14+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bağlamanın bir değerin kopyası değil, sahibine açılan bir bağ olduğunu ayırır'
    - 'Çocuğun ebeveyn durumunu yazdığı değişiklikte hangi görünümlerin yeniden hesaplandığını ölçer'
    - 'Çocuğun kendi geçici durumunun ebeveyn tetiğinden ayrı, yerel kaldığını gösterir'
    - 'Tetiğin değişikliği başlatana değil değerin sahibine göre belirlendiğini iki yönlü yazmayla doğrular'
---

# Bağlama

Bir bağlamayla ebeveynin durumunu yazan çocuğun ebeveyn tetiğiyle yeniden hesaplandığının ve tetiğin değişikliği kimin başlattığına değil değerin sahibine bağlı olduğunun ölçümü.

Önceki derste durumu ataya kaldırdık ve çocuğa iki şey verdik: değerin kendisi ve değeri değiştirmesi için bir kapanış. Bu iki parçanın birleşimi o kadar sık gerekir ki çerçevede tek bir kavrama dönüşmüştür: **bağlama** (binding). Bağlama, bir değerin kendisi değil, değerin sahibine açılan okuma ve yazma yoludur. Bu derste bakılan tetik **ebeveyn**: çocuk görünüm, sahibi başka olan bir değeri okuyor ve yazıyor.

Ölçüm aynı çekirdek dosyayla yapılır.

```swift
// Invalidation.swift — bir degisikligin hangi gorunumu hangi kaynak yoluyla yeniden hesaplattigini siniflandirir
enum Storage {
    case state(owner: String)
    case model(object: String)
    case environment
}

struct ViewNode {
    let name: String
    let parent: String?
    let reads: Set<String>

    init(_ name: String, parent: String?, reads: Set<String>) {
        self.name = name
        self.parent = parent
        self.reads = reads
    }
}

struct Recompute {
    let view: String
    let cause: String
}

struct ViewTree {
    let nodes: [ViewNode]
    let storage: [String: Storage]

    func ancestors(of name: String) -> [String] {
        var found: [String] = []
        var current = nodes.first { $0.name == name }?.parent
        while let next = current {
            found.append(next)
            current = nodes.first { $0.name == next }?.parent
        }
        return found
    }

    func cause(of node: ViewNode, key: String) -> String {
        guard let kind = storage[key] else { return "olcum-disi" }
        switch kind {
        case .environment:
            return "ortam"
        case .model:
            return "gozlem"
        case .state(let owner):
            if owner == node.name { return "yerel" }
            if ancestors(of: node.name).contains(owner) { return "ebeveyn" }
            return "kural-disi"
        }
    }

    func change(_ label: String, key: String) -> [Recompute] {
        let hits = nodes.filter { $0.reads.contains(key) }
            .map { Recompute(view: $0.name, cause: cause(of: $0, key: key)) }
        let skipped = nodes.filter { !$0.reads.contains(key) }.map(\.name)
        let recomputed = hits.isEmpty ? "yok" : hits.map { "\($0.view) \($0.cause)" }.joined(separator: ", ")
        let rest = skipped.isEmpty ? "yok" : skipped.joined(separator: ",")
        print("\(label): \(key) degisti | yeniden \(recomputed) | atlanan \(rest)")
        return hits
    }
}

func countCauses(_ recomputes: [Recompute]) {
    for cause in ["yerel", "ebeveyn", "gozlem", "ortam"] {
        print("\(cause): \(recomputes.filter { $0.cause == cause }.count)")
    }
}
```

Çekirdekte bağlamanın ayrı bir tipi yoktur. `Storage.state(owner:)` değerin sahibini söyler, `reads` hangi görünümün onu okuduğunu söyler. Bir bağlama üzerinden okuyan görünüm de okuyan görünümdür; model, çerçevenin bağımlılık izleme kuralını kurar, çerçevenin kendisi değildir.

## Sahibine Açılan Bağ

Bir ekranın ses düzeyini tuttuğunu düşünelim. Düzey ekranın durumudur; ekran onu bir adım düğmesine verir ve düğme düzeyi artırabilmelidir. Çocuk durumu sahiplenmez, bir bağlama alır. Ebeveyn bağlamayı değerin önüne `$` koyarak kurar; çocuk onu `@Binding` ile bildirir.

```swift
import SwiftUI

struct VolumeScreen: View {
    @State private var volume = 3

    var body: some View {
        VStack {
            Text("Ses: \(volume)")
            VolumeStepper(volume: $volume)
            FooterNote()
        }
    }
}

struct VolumeStepper: View {
    @Binding var volume: Int
    @State private var isPressed = false

    var body: some View {
        Button(isPressed ? "Basili" : "Yukselt \(volume)") {
            volume += 1
            isPressed = true
        }
    }
}
```

`VolumeStepper` iki farklı değere sahip. `volume` bir bağlamadır: değer ekrana aittir, çocuk onu yalnız okur ve yazar. `isPressed` ise çocuğun kendi durumudur: yalnız düğmeyi ilgilendirir, ekranın başka yerinde kimse bilmez. Önceki dersin ayrımı burada yan yana durur; biri ata–torun yolunda akan, öteki sahibinde kalan değerdir.

Ağaçta `VolumeScreen` ve `VolumeStepper` iki değeri paylaşır. `volume` ekranındır; ekranın gövdesi onu gösterir, düğmenin gövdesi de gösterir. `FooterNote` ise hiçbirini okumaz. İki değişiklik verilir: biri bağlamanın değeri, biri çocuğun geçici durumu.

```swift
// main.swift — baglama ebeveyn tetigi, cocugun kendi durumu yerel tetik uretir
let storage: [String: Storage] = [
    "volume": .state(owner: "VolumeScreen"),
    "isPressed": .state(owner: "VolumeStepper"),
]

let screen = ViewTree(nodes: [
    ViewNode("VolumeScreen", parent: nil, reads: ["volume"]),
    ViewNode("VolumeStepper", parent: "VolumeScreen", reads: ["volume", "isPressed"]),
    ViewNode("FooterNote", parent: "VolumeScreen", reads: []),
], storage: storage)

let recomputes = [
    screen.change("duzey-yukseldi", key: "volume"),
    screen.change("dugme-basildi", key: "isPressed"),
].flatMap { $0 }

countCauses(recomputes)
```

```
duzey-yukseldi: volume degisti | yeniden VolumeScreen yerel, VolumeStepper ebeveyn | atlanan FooterNote
dugme-basildi: isPressed degisti | yeniden VolumeStepper yerel | atlanan VolumeScreen,FooterNote
yerel: 2
ebeveyn: 1
gozlem: 0
ortam: 0
```

`duzey-yukseldi` satırında iki görünüm yeniden hesaplandı. `VolumeScreen` değerin sahibi, yerel; `VolumeStepper` değeri bir bağlamayla okuyan alt görünüm, ebeveyn. Düzeyi yazan çocuktu, ama çocuk sahibi değildi. `dugme-basildi` satırında yalnız `VolumeStepper` yeniden hesaplandı ve yerel: `isPressed` çocuğa aittir, bağlamayla ekrana bağlı değildir ve ekran bu değişiklikten haberdar olmaz. `FooterNote` iki değişiklikte de atlandı.

Sayılar şöyle çıkar: iki değişiklik üç yeniden hesaplama üretti; ikisi yerel, biri ebeveyn. Aynı çocuk görünüm iki satırda iki farklı tetikle göründü: bir değer bağlamayla geldiği için ebeveyn, bir değer kendisinin olduğu için yerel. Görünümün türü tetiği belirlemiyor, her okunan değerin sahibi belirliyor.

**DR4.** Bu ölçüm iki değişiklik ve iki anahtar için. Düğmenin eylemindeki iki atama tek bir değişiklik olarak ele alınmadı; `volume` ve `isPressed` ayrı ölçüldü. Çerçevenin iki değişikliği aynı döngüde birleştirip birleştirmediği ölçülmedi.

## Bağlama ile Parametre Aynı Tetiği Üretir

Çocuğa değeri bağlama yerine düz bir parametre olarak vermek de mümkündür. Parametreyi alan görünüm değeri okur ama yazamaz; yazmak için bir kapanışa ihtiyaç duyar, önceki dersteki düzen budur. Soru, tetiğin bu iki biçimde farklı olup olmadığıdır.

```swift
import SwiftUI

struct VolumeScreen: View {
    @State private var volume = 3

    var body: some View {
        VStack {
            VolumeStepper(volume: $volume)
            VolumeBadge(level: volume)
        }
    }
}

struct VolumeBadge: View {
    let level: Int

    var body: some View {
        Text("Duzey \(level)")
    }
}
```

`VolumeStepper` değeri yazabilen çocuktur, `VolumeBadge` yalnız gösteren. İkisi de aynı değeri okur. Ağaç iki çocuğu bir arada kurar ve tek bir değişiklik uygular.

```swift
// main.swift — okuyan cocuk baglamayla da parametreyle de ayni tetigi alir
let storage: [String: Storage] = [
    "volume": .state(owner: "VolumeScreen"),
]

let screen = ViewTree(nodes: [
    ViewNode("VolumeScreen", parent: nil, reads: ["volume"]),
    ViewNode("VolumeStepper", parent: "VolumeScreen", reads: ["volume"]),
    ViewNode("VolumeBadge", parent: "VolumeScreen", reads: ["volume"]),
], storage: storage)

let recomputes = [
    screen.change("duzey-yukseldi", key: "volume"),
].flatMap { $0 }

countCauses(recomputes)
```

```
duzey-yukseldi: volume degisti | yeniden VolumeScreen yerel, VolumeStepper ebeveyn, VolumeBadge ebeveyn | atlanan yok
yerel: 1
ebeveyn: 2
gozlem: 0
ortam: 0
```

Üç görünüm yeniden hesaplandı: ekran yerel, iki çocuk ebeveyn. Bağlamayla okuyan `VolumeStepper` ile parametreyle okuyan `VolumeBadge` arasında çıktıda fark yok. Bu bir bulgudur ve bir sınırdır. Bulgu şudur: yeniden hesaplamayı okuma tetikler, yazma yetkisi değil. Sınır şudur: model yazma yetkisini ayırmaz, `ViewNode` yalnız neyin okunduğunu söyler. Bağlamanın çocuğa yazma yolu vermesi kod düzeyinde bir fark; tetik düzeyinde değildir.

**DR5.** Bu ölçüm iki çocuğun ikisi de değeri gövdede okuduğu durum için. Bir çocuğun bağlamayı yalnız yazıp hiç okumadığı durum ölçülmedi; o durumda `reads` içine girmeyeceği için model onu atlanan olarak sınıflardı.

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

Bir değişikliği kimin başlattığı ile kimin tetiklendiği ayrı sorulardır. Çocuk bağlama üzerinden yazdığında akla gelen ilk okuma, tetiğin çocuğa ait olduğudur. Kural bunu söylemez: **kural yazanı okumaz**. Tetik, değerin sahibine ve okuyana bakar; değişikliği kimin yazdığına bakmaz. Aşağıdaki ölçüm bunu aynı anahtarın iki değişikliğiyle gösterir: biri çocuğun yazmasını, biri ebeveynin yazmasını temsil eder. Modelde ikisinin farkı yalnız etikettedir.

```swift
// main.swift — kural yazani okumaz, tetik degerin sahibine gore belirlenir
let storage: [String: Storage] = [
    "volume": .state(owner: "VolumeScreen"),
]

let screen = ViewTree(nodes: [
    ViewNode("VolumeScreen", parent: nil, reads: ["volume"]),
    ViewNode("VolumeStepper", parent: "VolumeScreen", reads: ["volume"]),
], storage: storage)

let recomputes = [
    screen.change("cocuk-yazdi", key: "volume"),
    screen.change("ebeveyn-yazdi", key: "volume"),
].flatMap { $0 }

countCauses(recomputes)
```

```
cocuk-yazdi: volume degisti | yeniden VolumeScreen yerel, VolumeStepper ebeveyn | atlanan yok
ebeveyn-yazdi: volume degisti | yeniden VolumeScreen yerel, VolumeStepper ebeveyn | atlanan yok
yerel: 2
ebeveyn: 2
gozlem: 0
ortam: 0
```

İki satır birebir aynı: ekran yerel, çocuk ebeveyn. Yazanın çocuk olması çocuğu yerel yapmadı. Sayımda yerel 2, ebeveyn 2 çıktı; yazan görünüm hiçbir sayıyı değiştirmedi. Bu dersin tetiği bu yüzden değişikliği çocuğun başlatmasıyla tanımlanmaz, çocuğun sahibi olmadığı bir değeri okumasıyla tanımlanır.

**DR6.** Bu ölçüm model düzeyinde bir eşitliği gösterir: aynı anahtar, aynı ağaç, aynı sonuç. Çerçevenin çocuktan gelen yazmayı ebeveynden gelen yazmadan farklı sıraladığı ya da gruplandığı ölçülmedi.

## Özet

- Bağlama, bir değerin kopyası değil, sahibine açılan okuma ve yazma yoludur.
- Bağlamayla ebeveyn durumunu okuyan çocuk, değer değişince ebeveyn tetiğiyle yeniden hesaplanır; durumun sahibi yerel tetikle yeniden hesaplanır.
- Çocuğun kendi geçici durumu bağlamadan bağımsızdır ve yalnız çocuğu yeniden hesaplatır, tetik yereldir.
- Bağlamayla okuyan ile parametreyle okuyan çocuk aynı tetiği alır; model yazma yetkisini ayırmaz.
- Kural yazanı okumaz: aynı değişiklik çocuktan da ebeveynden de gelse tetik değerin sahibine göre belirlenir.
- Bu dersin tetiği: **ebeveyn**.

## Sonraki Adım

Şimdiye kadar değerlerin hepsi bir görünümde yaşadı ve ya o görünümde ya da onun altında okundu. Sıradaki derste değer bir görünümde değil, ayrı bir nesnede yaşar ve onu okuyan görünümler ağacın herhangi bir yerinde olabilir. Soru aynı kalır, ama tetik yeni bir adla anılır: gözlem.
