---
title: 'Yerel Durum'
source: 'https://academia.sh/tr/kurslar/swiftui/yerel-durum'
course: 'SwiftUI ile Arayüz'
language: tr
updated: '2026-10-21T05:03:14+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Görünümün kendi durumunu, değerin sahibinin o görünüm olduğu yerel tetikle ilişkilendirir'
    - 'Aynı durumun ataya kaldırılmasının tetiği yerelden ebeveyne çevirdiğini ölçer'
    - 'Durumun yalnız sahibinden altındaki görünümlere aktığını, kardeşe akmadığını gösterir'
    - 'Durum kaldırmanın hangi görünümleri yeniden hesaplattığını okuma yollarından çıkarır'
---

# Yerel Durum

Bir görünümün kendi durumunun yalnız o görünümü yeniden hesaplattığının, aynı durum ataya kaldırılınca tetiğin ebeveyne döndüğünün ve kardeşin durumunun kural dışı kaldığının ölçümü.

Önceki konu görünümlerin nasıl kurulduğunu tamamladı: bir görünüm, değiştiricilerle ve kurucularla tarif edilen bir değerdi. Bu konu o tarifin içindeki değişkenlere bakar. Açılış dersinde altı değişikliğin sekiz yeniden hesaplama ürettiğini ve bunların ikisinin yerel olduğunu gördük; yerel iki satırın ikisi de bir görünümün **kendi** değerinden geliyordu. Bu derste bakılan tetik **yerel**: yeniden hesaplamayı, değerin sahibinin kendisi olan görünüm yaşıyor.

Ölçüm yine aşağıdaki çekirdek dosyayla yapılır. Ders boyunca değişmez, kurs boyunca her ders onu birebir verir.

```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)")
    }
}
```

`Storage.state(owner:)` bir değerin hangi görünüme ait olduğunu söyler. `cause` işlevi bu sahibi, değişiklikten etkilenen görünümle karşılaştırır: sahip görünümün kendisiyse tetik `yerel`, sahip görünümün bir atasıysa `ebeveyn`, ikisi de değilse `kural-disi` olur. Model, çerçevenin bağımlılık izleme kuralını kurar; çerçevenin kendisi değildir.

## Görünümün Kendi Durumu

Bir görünümün zamanla değişen ve yalnız kendisini ilgilendiren değeri **yerel durum** (local state) olarak tutulur. Bu değer bir özellik sarmalayıcısıyla, `@State` ile işaretlenir. Aşağıdaki görünüm bir dokunma sayacı tutar. Sayaç `private` işaretlidir: görünümün dışına açılmaz, yalnız görünümün kendi gövdesi onu okur ve yazar.

```swift
import SwiftUI

struct CounterCard: View {
    @State private var tapCount = 0

    var body: some View {
        VStack {
            Text("Dokunma: \(tapCount)")
            Button("Artir") { tapCount += 1 }
        }
    }
}
```

`@State` ile işaretlenen değer görünüm değerinin içinde değil, çerçevenin yönettiği bir depoda yaşar. Görünüm bir yapıdır ve her yeniden hesaplamada yeniden kurulabilir; sayaç ise kurulan her yeni değerde sıfırlanmaz, çünkü değeri saklayan görünüm değil depodur. Sahip, bu depoyu kendi kimliği üzerinden kullanan görünümdür. Bu ayrım ölçümde `owner` alanına dönüşür.

Aşağıdaki ağaçta `DashboardView` bir kök, `CounterCard` onun çocuğu ve `StatusLabel` onun ikinci çocuğudur. Yukarıdaki kaynak parçadaki tip ve özellik adları ağaçta aynen durur: anahtar `tapCount`, sahip `CounterCard`. Görünümlerin hangi değeri okuduğu, kaynaktaki gövdelere göre `reads` içindedir; `DashboardView` ve `StatusLabel` sayacı okumaz.

```swift
// main.swift — gorunumun kendi durumu yalniz kendini yeniden hesaplatir
let storage: [String: Storage] = [
    "tapCount": .state(owner: "CounterCard"),
]

let screen = ViewTree(nodes: [
    ViewNode("DashboardView", parent: nil, reads: []),
    ViewNode("CounterCard", parent: "DashboardView", reads: ["tapCount"]),
    ViewNode("StatusLabel", parent: "DashboardView", reads: []),
], storage: storage)

let recomputes = [
    screen.change("dokunuldu", key: "tapCount"),
].flatMap { $0 }

countCauses(recomputes)
```

```
dokunuldu: tapCount degisti | yeniden CounterCard yerel | atlanan DashboardView,StatusLabel
yerel: 1
ebeveyn: 0
gozlem: 0
ortam: 0
```

Tek değişiklik, tek yeniden hesaplama: yalnız `CounterCard` yeniden hesaplandı ve tetik `yerel`. `DashboardView` ve `StatusLabel` atlandı, çünkü hiçbiri `tapCount` değerini okumuyor. Bu, açılış dersindeki `satir-acildi` satırının aynısıdır: değer görünümün kendisinindir ve değişikliğin etkisi o görünümde kalır. Çıktının son dört satırında dört kategorinin sayımı görünür; yerel bir, geri kalan üçü sıfır.

Yerel durumun getirisi budur: değişikliğin kapsamı sahibin gövdesiyle sınırlıdır. Ekranın başka bir yerinde yaşayan görünüm sayacı bilmez ve bilmek zorunda da kalmaz.

**DR1.** Bu ölçüm tek bir değişiklik ve tek bir anahtar için. Sayaç değerinin görünümün yeniden kurulduğu her seferde korunduğu, modelde bir cümleyle anlatıldı ama ölçülmedi; modelin `ViewTree` tipi değerin ömrünü taşımaz.

## Durumu Ataya Kaldırmak

Başka bir görünüm de sayacı bilmek isterse yerel durum yetmez. Durumu, ilgilenen görünümlerin ortak atasına taşımak gerekir; buna **durum kaldırma** (state lifting) denir. Ata durumun sahibi olur, değeri çocuğa parametre olarak verir ve değeri değiştirmek için çocuğa bir kapanış iletir.

```swift
import SwiftUI

struct DashboardView: View {
    @State private var tapCount = 0

    var body: some View {
        VStack {
            CounterCard(tapCount: tapCount, onTap: { tapCount += 1 })
            StatusLabel()
        }
    }
}

struct CounterCard: View {
    let tapCount: Int
    let onTap: () -> Void

    var body: some View {
        VStack {
            Text("Dokunma: \(tapCount)")
            Button("Artir", action: onTap)
        }
    }
}
```

Görünüm yine aynı ekranı çiziyor; değişen, değerin yaşadığı yerdir. `CounterCard` artık `tapCount` saklamaz, yalnız ona verilen değeri gösterir. Sahip `DashboardView` olmuştur ve gövdesi değeri çocuğa ilettiği için onu okur. Sahiplik taşındığı için ağacın saklama tablosu da değişir: aynı anahtar, yeni bir sahip.

```swift
// main.swift — durum ataya kaldirilinca ayni anahtar ebeveyn tetigi uretir
let storage: [String: Storage] = [
    "tapCount": .state(owner: "DashboardView"),
]

let screen = ViewTree(nodes: [
    ViewNode("DashboardView", parent: nil, reads: ["tapCount"]),
    ViewNode("CounterCard", parent: "DashboardView", reads: ["tapCount"]),
    ViewNode("StatusLabel", parent: "DashboardView", reads: []),
], storage: storage)

let recomputes = [
    screen.change("dokunuldu", key: "tapCount"),
].flatMap { $0 }

countCauses(recomputes)
```

```
dokunuldu: tapCount degisti | yeniden DashboardView yerel, CounterCard ebeveyn | atlanan StatusLabel
yerel: 1
ebeveyn: 1
gozlem: 0
ortam: 0
```

Aynı değişiklik şimdi iki görünümü yeniden hesaplattı. `DashboardView` değerin sahibi olduğu için yerel; `CounterCard` değeri okuyan ama sahibi olmayan bir alt görünüm olduğu için ebeveyn. `StatusLabel` hâlâ atlanıyor: ata bir değeri sahiplendi diye her çocuğu yeniden hesaplatmaz, yalnız değeri okuyanları. Durum kaldırmanın bedeli bu: aynı dokunuş bir yerine iki yeniden hesaplama üretir. Karşılığında sayacı ekranın başka görünümleri de okuyabilir hâle gelir.

Sayılar önceki ölçümle kıyaslanınca tablo şöyle okunur: yerel durum bir yeniden hesaplama, yerel bir; ataya kaldırılmış durum iki yeniden hesaplama, yerel bir ve ebeveyn bir. Değişen şey değerin kendisi değil sahibidir. Aynı `CounterCard` ilk ölçümde `yerel`, ikincisinde `ebeveyn` tetikle yeniden hesaplandı; tetik görünümün türüne değil, değerin sahibine bağlıdır.

**DR2.** Bu ölçüm iki sahiplik düzeni için: sayaç ya `CounterCard` ya `DashboardView` tarafından sahiplenildi. Sahipliğin kök görünümden daha derindeki bir ataya kaldırılması ve birden çok çocuğun aynı değeri okuması ölçülmedi.

## Yerel Kalmalı mı, Kaldırılmalı mı

İki ölçüm bir karar kuralı verir ve kural değerin kimler tarafından okunduğuna bakar. Değeri yalnız bir görünüm okuyorsa durum o görünümde kalır: değişiklik tek yeniden hesaplama üretir ve başka görünümün gövdesine dokunmaz. Değeri birden çok görünüm okuyorsa durum bu görünümlerin en yakın ortak atasına çıkar; çünkü değerin tek bir doğruluk kaynağı olmalıdır. İki görünüm ayrı ayrı sayaç tutarsa iki sayaç birbirinden bağımsız değişir ve ekran aynı şeyi iki farklı biçimde gösterir.

İkinci ölçümün bir yan bulgusu da vardır: ata durumu sahiplenince çocuklar yeniden hesaplanır, ama bu yalnız değeri okuyan çocuklar için geçerlidir. Okumayan çocuk, ikinci ölçümdeki `StatusLabel` gibi, atlanır. Durumu mümkün olan en alçak ortak atada tutmak bu yüzden iki isteği birden karşılar: değeri okuyanlara ulaştırır, okumayanları etkilemez.

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

Durumun bir sahibi vardır ve değer yalnız sahibinden altındaki görünümlere akar. İki kardeş görünüm birbirinin durumuna ulaşamaz. Aşağıdaki ağaçta sayaç `CounterCard`'a aittir, ama kardeşi `ResetButton` da onu okuyor: bir ata–torun yolu yok, ikisi yalnız ortak bir atayı paylaşıyor.

```swift
// main.swift — kardesin durumunu okuyan gorunum kural disi kalir
let storage: [String: Storage] = [
    "tapCount": .state(owner: "CounterCard"),
]

let screen = ViewTree(nodes: [
    ViewNode("DashboardView", parent: nil, reads: []),
    ViewNode("CounterCard", parent: "DashboardView", reads: ["tapCount"]),
    ViewNode("ResetButton", parent: "DashboardView", reads: ["tapCount"]),
], storage: storage)

let recomputes = [
    screen.change("dokunuldu", key: "tapCount"),
].flatMap { $0 }

countCauses(recomputes)
```

```
dokunuldu: tapCount degisti | yeniden CounterCard yerel, ResetButton kural-disi | atlanan DashboardView
yerel: 1
ebeveyn: 0
gozlem: 0
ortam: 0
```

`CounterCard` yerel olarak yeniden hesaplandı. `ResetButton` ise sahibin ne atası ne kendisi olduğu için `kural-disi` satırı aldı: model bu okumayı dört kategoriden birine koyamaz. Bu bir kategori değildir ve `countCauses` bu satırı saymaz; altta yalnız `CounterCard`'ın yerel yeniden hesaplaması görünür. Kuralın söylediği şudur: durum, sahibine ve sahibinin altındaki görünümlere aittir. Bir kardeşin okuması gerekiyorsa durum ortak ataya kaldırılır; bu dersin ikinci bölümündeki düzen bunun yoludur.

**DR3.** Bu ölçüm yalnız bir kardeş okuması için ve modelin kurduğu kural içindir. Çerçevenin kardeşin durumuna ulaşmaya çalışan kodu nasıl işlediği ölçülmedi.

## Özet

- Görünümün kendi durumu yerel durumdur; değerin sahibi o görünümdür.
- Yerel durum değişince yalnız sahip görünüm yeniden hesaplanır, tetik yereldir.
- Durumu ataya kaldırmak sahibi değiştirir: ata yerel, değeri okuyan çocuk ebeveyn olur.
- Aynı görünüm, değerin sahibine bağlı olarak bir ölçümde yerel, ötekinde ebeveyn tetikle yeniden hesaplanır.
- Durum yalnız sahibinden altındaki görünümlere akar; kardeşin okuması `kural-disi` kalır ve sayılmaz.
- Bu dersin tetiği: **yerel**.

## Sonraki Adım

Durumu ataya kaldırdığımızda çocuğa bir değer ve bir kapanış verdik; çocuk değeri yalnız bu kapanış üzerinden değiştirebiliyordu. Sıradaki derste aynı iş tek bir kavramla yapılır: çocuğa değerin kendisi değil, değerin sahibine açılan bir bağ verilir. Soru aynı kalır, ama değişikliği çocuk başlatırken yeniden hesaplamayı kimin tetiklediği değişir.
