---
title: 'Görünüm Kurucular'
source: 'https://academia.sh/tr/kurslar/swiftui/gorunum-kurucular'
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 kurucunun birden çok ifadeyi tek bir görünüme nasıl topladığını kaynak parçada okur'
    - 'Kurucu içeriğindeki koşulun ebeveyn durumuna bağlı olduğunda ebeveyn tetiği ürettiğini ölçer'
    - 'Kurucu bileşenin kendi basılı durumunun yerel tetik ürettiğini gösterir'
    - 'İçerik kapanışının ağaçta düğüm olmadığını ve okumasının içeriği kuran görünüme ait olduğunu ölçer'
---

# Görünüm Kurucular

Kurucu içeriğindeki koşulun ebeveyn durumuna bağlı olduğunda ebeveyn tetiği ürettiğinin, kurucu bileşenin kendi basılı durumunun yerel kaldığının ve kapanışın ağaçta düğüm olmadığının ölçümü.

Önceki derste yapraklar değerlerini ortamdan, ebeveynden ve kendi bünyesinden aldı. Bu derste ağacı kuran araca bakıyoruz: görünüm kurucu. Bir gövdede alt alta yazılan ifadeler, bir koşul ya da bir döngü, kurucu tarafından tek bir görünüme toplanır. Kurucu bir bileşenin içeriği de bir kapanış olarak verilebilir. 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 açılır paneldir: paneli kuran ekran, panel, ayrıntı bloğu, basılabilir düğme ve etiketi.

## İfadelerden Görünüme

Görünüm kurucu, gövdedeki ifadeleri tek bir değerde toplayan bir yapıdır. İki metin alt alta yazıldığında ikisi birlikte tek bir görünüm olur; bir koşul yazıldığında doğru ve yanlış dalın yalnız biri gösterilir. Aşağıdaki parça panelin ayrıntı bloğunu bir koşula bağlar.

```swift
// Kaynak parca: kurucu koşulu ve ifadeleri tek gorunume toplar
import SwiftUI

struct DisclosurePanel: View {
    let showDetails: Bool
    let itemCount: Int

    var body: some View {
        VStack {
            Text("Oge sayisi: \(itemCount)")
            if showDetails {
                Text("Ayrintilar burada")
            }
        }
    }
}
```

`showDetails` panelin sahibinden gelen bir parametredir ve koşulun doğru ya da yanlış olmasını belirler. Koşul yanlışken ayrıntı bloğu ağaçta yoktur; doğruyken vardır. Modelde bu, ayrıntı bloğunun `showDetails` değerini okuyan bir düğüm olmasıdır.

**GV23.** Bu ölçüm koşullu bloğu her zaman ağaçta bulunan, ama `showDetails` değerini okuyan bir düğüm olarak modeller. Koşul yanlışken bloğun ağaçtan çıkması, yani kimliğin yok olması ve yeniden eklenmesi ölçülmedi.

## Koşul ve Kurucu Bileşen

Aşağıdaki ağaçta `showDetails` ve `itemCount` değerlerinin sahibi paneli kuran `PanelScreen`'dir; panel ikisini `let` parametresi olarak alır, ayrıntı bloğu ilkini okur. Basılabilir düğme kendi `isPressed` durumunun sahibidir ve etiketi bu değeri okuyarak vurgu verir.

```swift
// main.swift — kosul ebeveyn, kurucu bilesenin basili durumu yerel
let storage: [String: Storage] = [
    "showDetails": .state(owner: "PanelScreen"),
    "itemCount": .state(owner: "PanelScreen"),
    "isPressed": .state(owner: "PressableButton"),
]

let screen = ViewTree(nodes: [
    ViewNode("PanelScreen", parent: nil, reads: ["showDetails", "itemCount"]),
    ViewNode("DisclosurePanel", parent: "PanelScreen", reads: ["showDetails", "itemCount"]),
    ViewNode("DetailBlock", parent: "DisclosurePanel", reads: ["showDetails"]),
    ViewNode("PressableButton", parent: "DisclosurePanel", reads: ["isPressed"]),
    ViewNode("ButtonLabel", parent: "PressableButton", reads: ["isPressed"]),
], storage: storage)

let recomputes = [
    screen.change("detay-acildi", key: "showDetails"),
    screen.change("sayi-degisti", key: "itemCount"),
    screen.change("basildi", key: "isPressed"),
].flatMap { $0 }

countCauses(recomputes)
```

```
detay-acildi: showDetails degisti | yeniden PanelScreen yerel, DisclosurePanel ebeveyn, DetailBlock ebeveyn | atlanan PressableButton,ButtonLabel
sayi-degisti: itemCount degisti | yeniden PanelScreen yerel, DisclosurePanel ebeveyn | atlanan DetailBlock,PressableButton,ButtonLabel
basildi: isPressed degisti | yeniden PressableButton yerel, ButtonLabel ebeveyn | atlanan PanelScreen,DisclosurePanel,DetailBlock
yerel: 3
ebeveyn: 4
gozlem: 0
ortam: 0
```

`detay-acildi` satırında değerin sahibi olan ekran yerel, panel ile ayrıntı bloğu ebeveyn tetiğiyle yeniden hesaplandı; düğme ve etiketi atlandı. `sayi-degisti` satırında ekran yerel, panel ebeveyn tetiğiyle yeniden hesaplandı; ayrıntı bloğu sayıyı okumadığından atlandı. `basildi` satırında düğme yerel, etiket ebeveyn tetiğiyle yeniden hesaplandı.

Kurucu içeriğindeki koşul ebeveynin durumuna bağlıysa, koşulu kullanan blok ebeveyn tetiğiyle yeniden hesaplanır. Düğmenin kendi basılı durumu ise düğmenin dışına taşmaz: panel ve ayrıntı bloğu bu değişiklikte atlanır.

**GV24.** Bu ölçüm `showDetails`, `itemCount` ve `isPressed` için. Düğmenin basılı durumunun hangi hareket olayıyla değiştiği, yani dokunma ile kaldırma arasındaki geçiş ölçülmedi. Değerlerin sahibi olarak eklenen ekran bir model varsayımıdır; kaynak parça yalnız panelin parametrelerini gösterir.

## Kurucu Bileşen

Bir bileşenin içeriğini kapanış olarak almak, kurucu bileşenin tipik biçimidir. Bileşen kapanışı çağırır ve ortaya çıkan görünümü kendi düzeninin içine koyar. Aşağıdaki parça bir kart bileşenini kurucuyla tanımlar.

```swift
// Kaynak parca: icerigi kapanis olarak alan kurucu bilesen
import SwiftUI

struct InfoCard<Content: View>: View {
    @State private var isPressed = false
    let content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        content
            .padding()
            .opacity(isPressed ? 0.6 : 1)
            .onTapGesture { isPressed.toggle() }
    }
}
```

Bileşen, kendi basılı durumunun sahibidir ve içeriğin kendisine dokunmaz. Kullanan taraf kartın içeriğini kapanışla verir; kapanış çağrılır ve sonuç bir görünüm değeri olarak saklanır.

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

Kapanışın kendisi bir görünüm değildir. Bir değeri çağrıldığında üretir ve çağrıldığı yerde biter. Bu yüzden ağaçta bir düğüm olmaz; kapanışın içinde okunan değer, kapanışı çağıran görünüme değil, içeriği kuran görünüme aittir. Aşağıdaki ağaçta ekran, kartın içeriğini kurar; kart yalnız kabuktur.

```swift
// main.swift — kapanis agacta dugum degildir, okuma icerigi kuran gorunume aittir
let storage: [String: Storage] = [
    "title": .state(owner: "HostScreen"),
]

let screen = ViewTree(nodes: [
    ViewNode("HostScreen", parent: nil, reads: ["title"]),
    ViewNode("CardShell", parent: "HostScreen", reads: []),
    ViewNode("CardContent", parent: "CardShell", reads: ["title"]),
], storage: storage)

let recomputes = [
    screen.change("baslik-degisti", key: "title"),
    screen.change("kapanis-degisti", key: "contentClosure"),
].flatMap { $0 }

countCauses(recomputes)
```

```
baslik-degisti: title degisti | yeniden HostScreen yerel, CardContent ebeveyn | atlanan CardShell
kapanis-degisti: contentClosure degisti | yeniden yok | atlanan HostScreen,CardShell,CardContent
yerel: 1
ebeveyn: 1
gozlem: 0
ortam: 0
```

`baslik-degisti` satırında ekran yerel, içerik ebeveyn tetiğiyle yeniden hesaplandı; kart atlandı. Başlığı okuyan içeriktir, kabuk değildir. `kapanis-degisti` satırında hiçbir görünüm yeniden hesaplanmadı: kapanışın kendisi saklama tablosunda ve okuma kümelerinde yoktur, çünkü ağaçta düğüm olmaz.

**GV25.** Bu ölçüm kapanışı ağaçta düğüm olmayan bir yapı olarak ele alır ve onu bir anahtar olarak bile modellemez. Kapanışın hangi görünümün gövdesinde değerlendirildiği ve kurucunun içeriği ne zaman çağırdığı ölçülmedi.

## Özet

- Görünüm kurucu, gövdedeki ifadeleri, koşulları ve döngüleri tek bir görünüme toplar.
- Kurucu içeriğindeki koşul ebeveynin durumuna bağlıysa, koşulu kullanan blok ebeveyn tetiğiyle yeniden hesaplanır.
- Kurucu bileşenin kendi basılı durumu yerel tetik üretir ve bileşenin dışına taşmaz.
- İçerik kapanışı bir görünüm değildir ve ağaçta düğüm olmaz.
- Kapanışın içinde okunan değer, içeriği kuran görünüme aittir; kabuk onu okumaz.
- Bu dersin tetiği: **ebeveyn**.

## Sonraki Adım

Bu konuyu bitirdik: görünümler ağaçta nasıl kurulur ve değerler ağaçta nasıl akar. Sıradaki konu, bir görünümün kendi durumunu ele alır; ilk dersi Yerel Durum'dur: bir görünümün kendi sayacını saklaması neyi değiştirir, kim yeniden hesaplanır. Tetik yerel olacaktır.
