---
title: 'Yığıt Düzenleri'
source: 'https://academia.sh/tr/kurslar/swiftui/yigit-duzenleri'
course: 'SwiftUI ile Arayüz'
language: tr
updated: '2026-10-21T05:03:14+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Yatay, dikey ve derinlik yığıtlarının çocukları nasıl dizdiğini kaynak parçada okur'
    - 'Yığıtın aralık ve eksen değerlerinin çocuklara ebeveyn durumu olarak indiğini ölçer'
    - 'Yazı yönü gibi ortamdan okunan değerin yığıt değerinden farklı bir tetik ürettiğini gösterir'
    - 'Derinlik yığıtında üstteki görünümün alttakinin değerini okuyamadığını ölçer'
---

# Yığıt Düzenleri

Yığıtın aralık ve eksen değerlerinin ebeveyn durumundan çocuklara indiğinin, yön değerinin ortamdan okunduğunun ve derinlik yığıtında kardeş değerinin okunamadığının ölçümü.

Önceki derste bir değiştiricinin etkisinin alt ağaca ortam değeri olarak aktığını ölçtük. Bu derste aynı ağaçta çocukları dizen kapsayıcıya bakıyoruz: yığıt. Yığıt, çocuklarını yatayda, dikeyde ya da üst üste dizer ve aralarındaki boşluğu, hizalamayı kendi parametreleriyle belirler. Bu parametreler yığıtın sahibi olan görünümün durumundan gelir. Soru aynı kalır: **bu yeniden hesaplamayı ne tetikledi?** Bu derste bakılan tetik, **ebeveyn**.

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

Çekirdek, açılış dersindekiyle aynıdır. Bu dersin ağacı bir araç çubuğudur: çubuğu kuran ekran, çubuğu tutan yığıt ve içindeki simge, etiket ve rozet.

## Üç Yığıt, Üç Eksen

Yatay yığıt çocukları soldan sağa dizer, dikey yığıt yukarıdan aşağıya, derinlik yığıtı ise aynı alana üst üste koyar. İlk ikisinde aralık çocuklar arasındaki boşluğu, hizalama çocukların çapraz eksendeki konumunu belirler; üçüncüsünde yalnız hizalama vardır, çünkü çocuklar yan yana değil üst üste durur. Aşağıdaki parça üçünü bir arada gösterir.

```swift
// Kaynak parca: yatay, dikey ve derinlik yigiti
import SwiftUI

struct ToolbarStack: View {
    let spacing: Double
    let isVertical: Bool

    var body: some View {
        VStack(spacing: spacing) {
            HStack(spacing: spacing) {
                Image(systemName: "pencil")
                Text("Duzenle")
            }
            ZStack(alignment: isVertical ? .topTrailing : .bottomTrailing) {
                Image(systemName: "bell")
                Text("3")
            }
        }
    }
}
```

`spacing` ve `isVertical` saklanan değer değil, parametredir; yığıtı kuran görünüm ikisini de bir üst görünümden almıştır. Rozet ekseni okur: hizalaması `isVertical` değerine göre seçilir. Yığıtın içindeki çocuklar ise aralığı kendileri okumaz, yığıt aralığı çocukların arasına koyar. Bu ders modeli biraz sadeleştirir: yığıtın aralığına uyan her çocuk, aralığın değişmesiyle yeniden hesaplanan bir okuyucu sayılır. Bunun yaptığı şey, ebeveyn tetiğini görünür kılmaktır; çerçevenin aralığı çocuklara gerçekte nasıl ilettiğini göstermez.

**GV7.** Bu ölçüm yığıtın aralık ve eksen değerlerini çocuk görünümlerin okuduğu değerler olarak modeller. Çerçevenin yığıt değişince çocukları yeniden hesaplayıp hesaplamadığı ya da yalnız yerleşimi güncelleyip güncellemediği ölçülmedi.

## Yığıttan Çocuğa İnen Değer

Bir yığıtın aralığı ve ekseni, yığıtı kuran görünümün durumundan gelir. Çocuk bu değeri okuyorsa, değerin sahibi çocuğun bir atasıdır ve model tetiği ebeveyn olarak sınıflar. Aşağıdaki ağaçta iki değerin sahibi yığıtı kuran `ToolbarScreen`'dir; `ToolbarStack` ikisini de `let` parametresi olarak alır. Aralığı simge ve etiket, ekseni (`isVertical`) rozet okur. Yazı yönü ise ortam değeridir ve etiketle rozet tarafından okunur.

```swift
// main.swift — yigitin degerleri ebeveyn, yon degeri ortam tetigi uretir
let storage: [String: Storage] = [
    "spacing": .state(owner: "ToolbarScreen"),
    "isVertical": .state(owner: "ToolbarScreen"),
    "layoutDirection": .environment,
]

let screen = ViewTree(nodes: [
    ViewNode("ToolbarScreen", parent: nil, reads: ["spacing", "isVertical"]),
    ViewNode("ToolbarStack", parent: "ToolbarScreen", reads: ["spacing", "isVertical"]),
    ViewNode("ToolIcon", parent: "ToolbarStack", reads: ["spacing"]),
    ViewNode("ToolLabel", parent: "ToolbarStack", reads: ["spacing", "layoutDirection"]),
    ViewNode("ToolBadge", parent: "ToolbarStack", reads: ["isVertical", "layoutDirection"]),
], storage: storage)

let recomputes = [
    screen.change("aralik-degisti", key: "spacing"),
    screen.change("eksen-degisti", key: "isVertical"),
    screen.change("yon-degisti", key: "layoutDirection"),
].flatMap { $0 }

countCauses(recomputes)
```

```
aralik-degisti: spacing degisti | yeniden ToolbarScreen yerel, ToolbarStack ebeveyn, ToolIcon ebeveyn, ToolLabel ebeveyn | atlanan ToolBadge
eksen-degisti: isVertical degisti | yeniden ToolbarScreen yerel, ToolbarStack ebeveyn, ToolBadge ebeveyn | atlanan ToolIcon,ToolLabel
yon-degisti: layoutDirection degisti | yeniden ToolLabel ortam, ToolBadge ortam | atlanan ToolbarScreen,ToolbarStack,ToolIcon
yerel: 2
ebeveyn: 5
gozlem: 0
ortam: 2
```

`aralik-degisti` satırında değerin sahibi olan ekran yerel; yığıt, simge ve etiket ebeveyn tetiğiyle yeniden hesaplandı; rozet aralığı okumadığından atlandı. `eksen-degisti` satırında ekran yine yerel, yığıt ile rozet ebeveyn tetiğiyle yeniden hesaplandı; simge ve etiket atlandı. `yon-degisti` satırında ekran ile yığıt atlandı, etiket ve rozet ortam tetiğiyle yeniden hesaplandı: yazı yönü yığıtı kuran ekranın durumu değil, ağaca dışarıdan giren bir değerdir.

Sayaç da aynı hikâyeyi özetler: iki yerel, beş ebeveyn, iki ortam. Beş ebeveyn tetiği, değerlerin sahibinin tek bir değer değiştirmesinin kaç çocuğu etkileyebileceğini gösterir. Aralığı değiştiren bir görünüm, aralığı okuyan her çocuğu da yeniden hesaplatır.

**GV8.** Bu ölçüm `spacing`, `isVertical` ve `layoutDirection` için. Bir değerin hem yığıta hem de çocuğa parametre olarak geçtiği, aynı anahtarın iki yoldan okunduğu durum ölçülmedi. Değerlerin sahibi olarak eklenen ekran bir model varsayımıdır; kaynak parça yalnız yığıtın parametrelerini gösterir.

## Yön ve Eksen Seçimi

Yığıtın eksenini çalışma anında seçmek mümkündür: yatay ve dikey düzen arasında geçiş yapan bir düzen değeri, çocukları aynı kalırken eksenini değiştirir. Aşağıdaki parça bunu kaynak olarak gösterir.

```swift
// Kaynak parca: ekseni calisma aninda secen duzen
import SwiftUI

struct AdaptiveToolbar: View {
    let isVertical: Bool

    var body: some View {
        let layout = isVertical ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout())
        layout {
            Image(systemName: "pencil")
            Text("Duzenle")
        }
    }
}
```

`isVertical` bu görünümün `let` parametresidir, değerin sahibi onu kuran görünümdür; değer değişince yeni bir düzen değeri kurulur ve çocuklar aynı kalır. Modelde bu, `isVertical` anahtarının değişmesiyle aynıdır: değerin sahibi `ToolbarScreen` yerel tetikle, yığıt ve eksene bağlı çocuklar ebeveyn tetiğiyle yeniden hesaplanır. Yön ise ortamdan gelir ve düzen değeriyle ilgisi yoktur; sağdan sola yazılan bir dilde yatay yığıt çocuklarını tersten dizer, ama bu, yığıtın sahibinin kararı değildir.

**GV9.** Eksen seçimi bu derste yalnız kaynak parçada ve `isVertical` anahtarının modeldeki karşılığıyla ele alındı. Düzen değerinin değişmesinin çocukların kimliğini koruyup korumadığı ölçülmedi.

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

Derinlik yığıtında çocuklar aynı alanı paylaşır, ama kaynakta biri ötekinin `@State` değerine ulaşamaz: `@State` görünüme özeldir ve kardeş onu ne okuyabilir ne yazabilir. Bu kısıt yığıttan değil, `@State`'in görünüme özel olmasından gelir; yatay ya da dikey yığıttaki kardeşler için de aynıdır. Model bu kaynak kısıtını kendi kuralıyla taklit eder: değerin sahibi okuyanın atası değilse okuma `kural-disi` sayılır. Aşağıdaki ağaç kaynakta yazılamayacak bu okumayı modelde bilerek kurar: fotoğraf katmanı kendi `photoName` değerinin sahibidir, bindirme katmanı da bu değeri okuyormuş gibi modellenir.

```swift
// main.swift — derinlik yiginindaki kardes, digerinin degerini okuyamaz
let storage: [String: Storage] = [
    "photoName": .state(owner: "PhotoLayer"),
    "caption": .state(owner: "PhotoOverlay"),
]

let screen = ViewTree(nodes: [
    ViewNode("PhotoStack", parent: nil, reads: []),
    ViewNode("PhotoLayer", parent: "PhotoStack", reads: ["photoName"]),
    ViewNode("PhotoOverlay", parent: "PhotoStack", reads: ["caption", "photoName"]),
], storage: storage)

let recomputes = [
    screen.change("foto-degisti", key: "photoName"),
    screen.change("yazi-degisti", key: "caption"),
].flatMap { $0 }

countCauses(recomputes)
```

```
foto-degisti: photoName degisti | yeniden PhotoLayer yerel, PhotoOverlay kural-disi | atlanan PhotoStack
yazi-degisti: caption degisti | yeniden PhotoOverlay yerel | atlanan PhotoStack,PhotoLayer
yerel: 2
ebeveyn: 0
gozlem: 0
ortam: 0
```

`foto-degisti` satırında fotoğraf katmanı yerel, bindirme `kural-disi` olarak işaretlendi. Model, değerin sahibinin okuyanın atası olmadığını görür ve bu okumayı kural dışı sayar; bu bir çerçeve davranışının ölçümü değil, modelin kurulmaması gereken bir okumayı yakalamasıdır. İki katmanın aynı değeri kullanması gerekiyorsa değer ortak ataya, burada `PhotoStack`'e taşınır; o zaman iki katman da onu ebeveyn tetiğiyle okur. `yazi-degisti` satırında yalnız bindirme yeniden hesaplandı.

Sayaçta kural dışı tetik görünmez, çünkü `countCauses` yalnız dört tetiği sayar: yerel iki, ötekiler sıfır. Bu, sayaçtaki toplamın her zaman yeniden hesaplama sayısına eşit olmadığını gösterir; sayılmayan tetikler ayrıca okunmalıdır.

**GV10.** Bu ölçüm iki kardeş görünüm ve tek bir paylaşılan anahtar için. Çerçevenin kardeşler arasında değer aktarma yollarını, örneğin tercih anahtarlarını, ölçmedik.

## Özet

- Yığıt çocuklarını yatayda, dikeyde ya da üst üste dizer; aralık ve hizalama yığıtın parametreleridir.
- Yığıtı kuran görünümün durumundan gelen aralık ve eksen, yığıt ve çocuklar için ebeveyn tetiği üretir.
- Yazı yönü ortamdan gelir; yığıtın sahibinin durumu olmadığı için ortam tetiği üretir.
- Eksen seçimi, yığıtın sahibinin tek bir değeriyle yığıtı ve ona bağlı çocukları etkiler.
- Kardeşler, aynı alanı paylaşan derinlik yığıtında bile birbirinin `@State` değerini okuyamaz; kısıt `@State`'in görünüme özel olmasından gelir, model bu okumayı kural dışı sınıflar.
- Bu dersin tetiği: **ebeveyn**.

## Sonraki Adım

Bu derste yığıtın aralığı ve ekseni, sahibi olan ebeveynden çocuklara indi. Sıradaki derste aynı iniş boyutlar için işler: bir ebeveyn çocuğuna ne kadar yer önerdiğini nasıl belirler ve bu öneri hangi değere bağlıdır. Soru aynı kalır, ama bu kez değer bir aralık değil, bir boyut önerisidir.
