---
title: 'Izgara ve Geometri'
source: 'https://academia.sh/tr/kurslar/swiftui/izgara-ve-geometri'
course: 'SwiftUI ile Arayüz'
language: tr
updated: '2026-10-21T05:03:14+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Izgaranın sütun tanımından hücre düzenini nasıl kurduğunu kaynak parçada okur'
    - 'Yatay boyut sınıfının sütun sayısını ortam değeri olarak belirlediğini ölçer'
    - 'Izgara verisini veren ebeveyn durumunun hücrelere ebeveyn tetiği olarak indiğini gösterir'
    - 'Geometri okuyucunun verdiği boyutun durum olmadığını ve modelin onu ölçüm dışı bıraktığını ölçer'
---

# Izgara ve Geometri

Boyut sınıfının ızgara sütunlarını ortam değeri olarak belirlediğinin, ızgara verisinin ebeveynden indiğinin ve ölçülen boyutun durum olmadığı için ölçüm dışı kaldığının ölçümü.

Önceki derste önerilen boyutu belirleyen değer ebeveynin durumuydu. Bu derste bir ızgaranın kaç sütun gösterdiğine bakıyoruz ve cevabın bir kısmı ağacın dışından geliyor: ekranın yatay boyut sınıfı. Bir ızgara sütun tanımlarından hücre düzenini kurar; sütun sayısı ise çoğunlukla ızgarayı kuran görünümün ortamdan okuduğu bir değere bağlıdır. Soru aynı kalır: **bu yeniden hesaplamayı ne tetikledi?** Bu derste bakılan tetik, **ortam**.

```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 galeridir: galeri ekranı, ızgara, hücre ve alt yazı.

## Sütun Tanımından Izgaraya

Tembel dikey ızgara, sütun tanımlarının listesinden düzenini kurar. Üç esnek sütun, hücreleri üç sütuna dizer; tanım listesi kısaldığında aynı hücreler daha az sütuna yayılır. Aşağıdaki parça sütun sayısını yatay boyut sınıfına bağlar.

```swift
// Kaynak parca: sutun sayisini boyut sinifi belirler
import SwiftUI

struct GalleryGrid: View {
    @Environment(\.horizontalSizeClass) private var sizeClass
    let names: [String]

    var body: some View {
        let count = sizeClass == .compact ? 2 : 4
        let columns = Array(repeating: GridItem(.flexible()), count: count)
        LazyVGrid(columns: columns) {
            ForEach(names, id: \.self) { name in
                Text(name)
            }
        }
    }
}
```

`sizeClass` ortamdan okunur ve ızgaranın sütun sayısını belirler. Ekran döndüğünde ya da pencere boyutu değiştiğinde değer değişir ve ızgaranın gövdesi yeniden hesaplanır. `names` ise ızgarayı kuran görünümden gelen bir parametredir.

**GV14.** Bu ölçüm yatay boyut sınıfını tek bir ortam anahtarı olarak ele alır. Boyut sınıfının hangi eşikte değiştiği ve değerin hangi pencere genişliğine karşılık geldiği ölçülmedi.

## Boyut Sınıfı ve Izgara Verisi

Aşağıdaki ağaçta galeri ekranı bir süzgeç etiketinin sahibidir; ızgara ve hücre bu etiketi okur. Izgara aynı zamanda kendi fotoğraf sayısının sahibidir ve boyut sınıfını ortamdan okur. Alt yazı da boyut sınıfını okur, çünkü küçük ekranda tek satıra sığması gerekir.

```swift
// main.swift — boyut sinifi ortam, izgara verisi ebeveyn, fotograf sayisi yerel
let storage: [String: Storage] = [
    "horizontalSizeClass": .environment,
    "filterTag": .state(owner: "GalleryScreen"),
    "photoCount": .state(owner: "GalleryGrid"),
]

let screen = ViewTree(nodes: [
    ViewNode("GalleryScreen", parent: nil, reads: ["filterTag"]),
    ViewNode("GalleryGrid", parent: "GalleryScreen", reads: ["horizontalSizeClass", "photoCount", "filterTag"]),
    ViewNode("GalleryCell", parent: "GalleryGrid", reads: ["filterTag"]),
    ViewNode("GalleryCaption", parent: "GalleryGrid", reads: ["horizontalSizeClass"]),
], storage: storage)

let recomputes = [
    screen.change("sinif-degisti", key: "horizontalSizeClass"),
    screen.change("etiket-degisti", key: "filterTag"),
    screen.change("adet-degisti", key: "photoCount"),
].flatMap { $0 }

countCauses(recomputes)
```

```
sinif-degisti: horizontalSizeClass degisti | yeniden GalleryGrid ortam, GalleryCaption ortam | atlanan GalleryScreen,GalleryCell
etiket-degisti: filterTag degisti | yeniden GalleryScreen yerel, GalleryGrid ebeveyn, GalleryCell ebeveyn | atlanan GalleryCaption
adet-degisti: photoCount degisti | yeniden GalleryGrid yerel | atlanan GalleryScreen,GalleryCell,GalleryCaption
yerel: 2
ebeveyn: 2
gozlem: 0
ortam: 2
```

`sinif-degisti` satırında ızgara ve alt yazı ortam tetiğiyle yeniden hesaplandı; ekran ve hücre atlandı. Hücre sütun sayısını bilmez, yalnız kendi içeriğini çizer. `etiket-degisti` satırında ekran yerel, ızgara ve hücre ebeveyn tetiğiyle yeniden hesaplandı. `adet-degisti` satırında yalnız ızgara yerel tetikle yeniden hesaplandı: fotoğraf sayısının sahibi ızgaranın kendisidir.

Üç tetik üç farklı yoldan geldi: ortam, ebeveyn ve yerel. Izgara en çok okuyan görünümdür ve bu yüzden en çok yeniden hesaplanan görünümdür; her değişiklikte ızgara listede yer aldı, ekran ve hücre ise yalnız süzgeç değiştiğinde.

**GV15.** Bu ölçüm `horizontalSizeClass`, `filterTag` ve `photoCount` için. Izgaranın sütun sayısı değişince hücrelerin yeniden hesaplanıp hesaplanmadığı, yani çerçevenin hücre kimliğini nasıl koruduğu ölçülmedi.

## Geometri Okuyucu

Geometri okuyucu, kendisine önerilen boyutu ve koordinatları içeriğine verir. İçerik bu boyuta göre kendini çizer. Aşağıdaki parça okuyucunun verdiği genişliğe göre iki dala ayrılır.

```swift
// Kaynak parca: geometri okuyucunun verdigi genislige gore cizim
import SwiftUI

struct AdaptiveBanner: View {
    var body: some View {
        GeometryReader { proxy in
            if proxy.size.width > 400 {
                Text("Genis gorunum")
            } else {
                Text("Dar gorunum")
            }
        }
    }
}
```

Okuyucunun verdiği `proxy.size` bir durum değeri değildir: kimse onu kaydetmez ve kimse onun sahibi değildir. Değer, düzen geçişinde ebeveynin önerdiği boyuttan hesaplanır. Bu yüzden modelde geometrinin bir saklama yeri yoktur.

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

Aşağıdaki ağaçta okuyucu `readerSize` değerini okuyor gibi yazılmıştır, ama bu anahtar saklama tablosunda yoktur. Tabloda yalnız ekranın kendi modu vardır.

```swift
// main.swift — geometri okuyucunun boyutu tabloda yoksa tetik olcum disidir
let storage: [String: Storage] = [
    "mode": .state(owner: "ReaderScreen"),
]

let screen = ViewTree(nodes: [
    ViewNode("ReaderScreen", parent: nil, reads: ["mode"]),
    ViewNode("SizeReader", parent: "ReaderScreen", reads: ["mode", "readerSize"]),
    ViewNode("ReaderLabel", parent: "ReaderScreen", reads: ["mode"]),
], storage: storage)

let recomputes = [
    screen.change("boyut-olculdu", key: "readerSize"),
    screen.change("mod-degisti", key: "mode"),
].flatMap { $0 }

countCauses(recomputes)
```

```
boyut-olculdu: readerSize degisti | yeniden SizeReader olcum-disi | atlanan ReaderScreen,ReaderLabel
mod-degisti: mode degisti | yeniden ReaderScreen yerel, SizeReader ebeveyn, ReaderLabel ebeveyn | atlanan yok
yerel: 1
ebeveyn: 2
gozlem: 0
ortam: 0
```

`boyut-olculdu` satırı çekirdeğin ölçemediği satırdır: okuyucu değeri okuduğu için listelenir, ama satır `olcum-disi` yazar ve bir yeniden hesaplama iddiası değildir; ekran ve etiket atlanan olarak görünür. Model burada hiçbir boyut hesabı yapmaz: yalnız okunan anahtarın tabloda olmadığını görür ve tetiği ölçüm dışı sayar. `mod-degisti` satırında ise tabloda olan değer için ekran yerel, okuyucu ve etiket ebeveyn tetiğiyle yeniden hesaplandı.

**GV16.** Bu ölçüm geometriyi tek bir tablo dışı anahtara indirger. Gerçek bir geometri değişiminin hangi görünümleri yeniden hesaplattığı, okuyucunun düzen geçişinde kaç kez çağrıldığı ve koordinat alanlarının davranışı ölçülmedi.

## Özet

- Izgara, sütun tanımlarından hücre düzenini kurar; sütun sayısı sık sık bir ortam değerine bağlıdır.
- Yatay boyut sınıfı ortamdan okunur ve okuyan ızgara ile alt yazı ortam tetiğiyle yeniden hesaplanır.
- Izgara verisini veren ebeveyn durumu, hücreler için ebeveyn tetiği üretir.
- Izgaranın kendi sahip olduğu değer yerel tetik üretir.
- Geometri okuyucunun verdiği boyut durum değildir; modelde anahtarı yoksa tetik ölçüm dışı sınıflanır.
- Bu dersin tetiği: **ortam**.

## Sonraki Adım

Bu derste ızgaranın verisi ve boyut sınıfı iki ayrı yoldan geldi. Sıradaki derste aynı soruyu liste için soruyoruz: bir listenin satırları, kendi ağacının dışında yaşayan bir modelin koleksiyonuna bağlandığında ne olur. Bu kez tetik, ağacın dışındaki bir modelden gelir.
