---
title: 'Çerçeve Seçimi'
source: 'https://academia.sh/tr/kurslar/uikit/cerceve-secimi'
course: 'UIKit ve Köprüleme'
language: tr
updated: '2026-10-21T05:03:15+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Aynı modelin bildirimsel ve buyurgan iki ekranını aynı kuralla denetler'
    - 'Buyurgan tarafta unutulan alanın eksik, güncellenmeyen alanın bayat ölçüldüğünü gösterir'
    - 'Uyumun bir çerçeve seçim ölçütü olmadığını iki yönde bozulan ekranla doğrular'
    - 'Seçim gerekçelerini ekip, eski kod, platform sürümü ve özel çizim üzerinden sayıya dökmeden anlatır'
---

# Çerçeve Seçimi

Aynı modelden bildirimsel ve buyurgan iki ekran kurup aynı kuralla denetlemenin ölçümü ve uyumun bir çerçeve seçim ölçütü olmadığının gösterimi; kursun on beş dersinin kapanış tablosu.

Önceki derste eski bir ekranı ekran ekran yeni çerçeveye taşıdık ve kuralın alan başına çalıştığını gördük. Bu konunun son sorusu kaçınılmaz olarak şudur: yeni bir ekran yazılacaksa hangi çerçeve seçilmeli? Kursun ölçüsü bu soruya cevap vermez, ve bu dersin işi tam olarak bunu göstermektir. Ölçü ekseni değişmedi: **uyum**. Çekirdek dosya önceki derslerle aynıdır.

```swift
// Sync.swift — ekranda gosterilen her alani modelin o anki degeriyle karsilastirir
final class Screen {
    let name: String
    private(set) var shown: [String: String] = [:]

    init(_ name: String) { self.name = name }

    func set(_ key: String, _ value: String) { shown[key] = value }
    func clear(_ key: String) { shown[key] = nil }
}

func verdict(model: String?, shown: String?) -> String {
    switch (model, shown) {
    case (nil, nil): return "olcum-disi"
    case (nil, _?): return "artik"
    case (_?, nil): return "eksik"
    case let (wanted?, displayed?): return wanted == displayed ? "uyumlu" : "bayat"
    }
}

func check(_ label: String, model: [String: String], screen: Screen, keys: [String]) -> [String] {
    keys.map { key in
        let result = verdict(model: model[key], shown: screen.shown[key])
        print("\(label) | \(screen.name).\(key): model=\(model[key] ?? "-") ekran=\(screen.shown[key] ?? "-") -> \(result)")
        return result
    }
}

func countVerdicts(_ verdicts: [String]) {
    for name in ["uyumlu", "bayat", "eksik", "artik"] {
        print("\(name): \(verdicts.filter { $0 == name }.count)")
    }
}
```

## Aynı Model, İki Ekran

Bir profil ekranı üç değer gösteriyor: ad, okunmamış sayısı ve durum. Model tek bir değer tipidir. Bildirimsel çerçevede ekran bu modelin bir işlevidir.

```swift
import SwiftUI

struct ProfileView: View {
    let model: ProfileModel

    var body: some View {
        VStack {
            Text(model.title)
            Text(String(model.unread))
            Text(model.status)
        }
    }
}
```

Buyurgan çerçevede aynı üç değeri kod, üç etikete tek tek yazar.

```swift
import UIKit

final class ProfileController: UIViewController {
    @IBOutlet private var titleLabel: UILabel!
    @IBOutlet private var unreadLabel: UILabel!
    @IBOutlet private var statusLabel: UILabel!

    func render(_ model: ProfileModel) {
        titleLabel.text = model.title
        unreadLabel.text = String(model.unread)
        statusLabel.text = model.status
    }
}
```

Model, kodun ekrana ne yazdığını kurar; çerçevenin kendisi değildir. İki ekranın yazdığı değerler yardımcı dosyada durur ve adlar KAYNAK parçalardakilerle aynıdır.

```swift
// Profile.swift — ayni modelden kurulan iki ekran
struct ProfileModel {
    var title: String
    var unread: Int
    var status: String

    var values: [String: String] {
        ["title": title, "unread": String(unread), "status": status]
    }
}

struct ProfileView {
    let model: ProfileModel

    func body(on screen: Screen) {
        screen.set("title", model.title)
        screen.set("unread", String(model.unread))
        screen.set("status", model.status)
    }
}

final class ProfileController {
    let screen = Screen("ProfileController")

    func render(_ model: ProfileModel) {
        screen.set("title", model.title)
        screen.set("unread", String(model.unread))
        screen.set("status", model.status)
    }
}
```

İlk olay: aynı model iki ekrana verilir.

```swift
// main.swift — ayni model iki ekrana yazilir
let model = ProfileModel(title: "Ayse", unread: 3, status: "cevrimici")
let keys = ["title", "unread", "status"]

let declarative = Screen("ProfileView")
ProfileView(model: model).body(on: declarative)
let controller = ProfileController()
controller.render(model)

let viaDeclarative = check("ayni-model-bildirimsel", model: model.values, screen: declarative, keys: keys)
let viaImperative = check("ayni-model-buyurgan", model: model.values, screen: controller.screen, keys: keys)

countVerdicts(viaDeclarative + viaImperative)
```

```
ayni-model-bildirimsel | ProfileView.title: model=Ayse ekran=Ayse -> uyumlu
ayni-model-bildirimsel | ProfileView.unread: model=3 ekran=3 -> uyumlu
ayni-model-bildirimsel | ProfileView.status: model=cevrimici ekran=cevrimici -> uyumlu
ayni-model-buyurgan | ProfileController.title: model=Ayse ekran=Ayse -> uyumlu
ayni-model-buyurgan | ProfileController.unread: model=3 ekran=3 -> uyumlu
ayni-model-buyurgan | ProfileController.status: model=cevrimici ekran=cevrimici -> uyumlu
uyumlu: 6
bayat: 0
eksik: 0
artik: 0
```

Altı alanın altısı uyumlu. Buyurgan tarafta bunun sebebi kodun üç alanı da yazmasıdır; bildirimsel tarafta ise çerçevenin okuyanı yeniden hesaplamasıdır.

**KP21.** Model, bildirimsel görünümün `body` içinde yazdığı değerleri ekrana yazılmış kabul eder ve modelde yeniden hesaplamayı `body`yi yeniden çağırarak kurar. Çerçevenin hesabı ne zaman yaptığı ölçülmez; bu bir varsayımdır.

## Buyurgan Tarafta Unutulan Alan

Aynı ekran buyurgan çerçevede yazılırken bir satırın düşmesi çok kolaydır. İki olay kuralım. Birincisinde denetleyici durum etiketini hiç yazmaz. İkincisinde ekran doğru kurulur, sonra model değişir ve değişimi gören kod ekranı yeniden yazmaz.

```swift
// main.swift — buyurgan denetleyici durumu unutur, sonra model degisir
final class ForgetfulProfileController {
    let screen = Screen("ForgetfulProfileController")

    func render(_ model: ProfileModel) {
        screen.set("title", model.title)
        screen.set("unread", String(model.unread))
    }
}

let model = ProfileModel(title: "Ayse", unread: 3, status: "cevrimici")
let keys = ["title", "unread", "status"]

let forgetful = ForgetfulProfileController()
forgetful.render(model)
let declarative = Screen("ProfileView")
ProfileView(model: model).body(on: declarative)

let missingDeclarative = check("buyurgan-unuttu-bildirimsel", model: model.values, screen: declarative, keys: keys)
let missingImperative = check("buyurgan-unuttu-buyurgan", model: model.values, screen: forgetful.screen, keys: keys)

let latest = ProfileModel(title: "Ayse", unread: 5, status: "cevrimici")
let refreshed = Screen("ProfileView")
ProfileView(model: latest).body(on: refreshed)
let careful = ProfileController()
careful.render(model)

let changedDeclarative = check("model-degisti-bildirimsel", model: latest.values, screen: refreshed, keys: keys)
let changedImperative = check("model-degisti-buyurgan", model: latest.values, screen: careful.screen, keys: keys)

countVerdicts(missingDeclarative + missingImperative + changedDeclarative + changedImperative)
```

```
buyurgan-unuttu-bildirimsel | ProfileView.title: model=Ayse ekran=Ayse -> uyumlu
buyurgan-unuttu-bildirimsel | ProfileView.unread: model=3 ekran=3 -> uyumlu
buyurgan-unuttu-bildirimsel | ProfileView.status: model=cevrimici ekran=cevrimici -> uyumlu
buyurgan-unuttu-buyurgan | ForgetfulProfileController.title: model=Ayse ekran=Ayse -> uyumlu
buyurgan-unuttu-buyurgan | ForgetfulProfileController.unread: model=3 ekran=3 -> uyumlu
buyurgan-unuttu-buyurgan | ForgetfulProfileController.status: model=cevrimici ekran=- -> eksik
model-degisti-bildirimsel | ProfileView.title: model=Ayse ekran=Ayse -> uyumlu
model-degisti-bildirimsel | ProfileView.unread: model=5 ekran=5 -> uyumlu
model-degisti-bildirimsel | ProfileView.status: model=cevrimici ekran=cevrimici -> uyumlu
model-degisti-buyurgan | ProfileController.title: model=Ayse ekran=Ayse -> uyumlu
model-degisti-buyurgan | ProfileController.unread: model=5 ekran=3 -> bayat
model-degisti-buyurgan | ProfileController.status: model=cevrimici ekran=cevrimici -> uyumlu
uyumlu: 10
bayat: 1
eksik: 1
artik: 0
```

Unutulan `status` alanı buyurgan ekranda **eksik**, güncellenmeyen `unread` alanı **bayat** çıktı; bildirimsel ekranın altı alanı uyumludur. Yani buyurgan çerçeve, programcının yazmayı unutabileceği yer sayısını artırır. Bu bir kusur değil, çerçevenin işi programcıya geri vermesinin bedelidir: ekran üzerindeki denetim de o kadar fazladır.

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

Bu bedel, uyumu bir seçim ölçütü yapmaz. Kural ekranı hangi çerçevenin kurduğunu bilmez; ekranın ne gösterdiğine bakar ve bozulma iki yönde de mümkündür. Titiz yazılmış bir buyurgan denetleyici tüm alanları uyumlu tutar. Bildirimsel bir görünüm ise modelde olmayan sabit bir metni gösterebilir; sabit metin her yeniden hesaplamada aynen yazılır.

```swift
// main.swift — bozulma iki cercevede de olur
struct BannerProfileView {
    let model: ProfileModel

    func body(on screen: Screen) {
        screen.set("title", model.title)
        screen.set("unread", String(model.unread))
        screen.set("status", model.status)
        screen.set("banner", "yeni")
    }
}

let model = ProfileModel(title: "Ayse", unread: 3, status: "cevrimici")
let keys = ["title", "unread", "status", "banner"]

let careful = ProfileController()
careful.render(model)
let banner = Screen("BannerProfileView")
BannerProfileView(model: model).body(on: banner)

let carefulResult = check("sinir-buyurgan", model: model.values, screen: careful.screen, keys: keys)
countVerdicts(carefulResult)
let bannerResult = check("sinir-bildirimsel", model: model.values, screen: banner, keys: keys)
countVerdicts(bannerResult)
```

```
sinir-buyurgan | ProfileController.title: model=Ayse ekran=Ayse -> uyumlu
sinir-buyurgan | ProfileController.unread: model=3 ekran=3 -> uyumlu
sinir-buyurgan | ProfileController.status: model=cevrimici ekran=cevrimici -> uyumlu
sinir-buyurgan | ProfileController.banner: model=- ekran=- -> olcum-disi
uyumlu: 3
bayat: 0
eksik: 0
artik: 0
sinir-bildirimsel | BannerProfileView.title: model=Ayse ekran=Ayse -> uyumlu
sinir-bildirimsel | BannerProfileView.unread: model=3 ekran=3 -> uyumlu
sinir-bildirimsel | BannerProfileView.status: model=cevrimici ekran=cevrimici -> uyumlu
sinir-bildirimsel | BannerProfileView.banner: model=- ekran=yeni -> artik
uyumlu: 3
bayat: 0
eksik: 0
artik: 1
```

Buyurgan ekran üç uyumlu verdi ve `banner` ölçüm dışında kaldı. Bildirimsel ekran aynı üç uyumluyu ve bir **artık** verdi. İlk bakışta iki ekrandan biri "daha uyumlu" görünür, ama iki çerçevenin sayısı birbirini sıralamaz: aynı kural, aynı model, kodun yazdığı farklı hatalar.

**KP22.** Model, ekranı kuran çerçeveyi bilmez; yalnız ekranın gösterdiği alanları karşılaştırır. Çerçeve seçiminin gerekçeleri ölçülmez, ve bu derste sayıya dökülmez.

Gerçek gerekçeler başka yerdedir ve hepsi düzyazıyla tartılır.

- **Ekip.** Ekibin bildirimsel çerçeveyi bilmesi, ekran başına yazılan satırın azalması demektir; ekip buyurgan çerçeveyi biliyorsa öğrenme maliyeti yeni çerçevenin getirdiği kazancı aşabilir.
- **Eski kod.** Çalışan bir ekranı yeniden yazmak, risk taşır. Önceki dersteki kademeli yol, bu riski ekran başına küçültür.
- **Platform sürümü.** Bildirimsel çerçeve her hedef sürümde bulunmaz; desteklenecek en düşük sürüm çerçeveyi seçmeden önce belirlenir.
- **Özel çizim.** Elle çizilen ya da katman animasyonlu bir parça, buyurgan çerçevenin sunduğu denetime ihtiyaç duyabilir; bildirimsel ekran onu sarmalayarak alır.

Bu dört gerekçeden hiçbiri bir sayı değildir, ve ölçümümüz bu kararı vermeye yetmez.

## Özet

- Aynı model iki çerçeveyle kurulunca iki ekran da altı alanda uyumludur (6 uyumlu).
- Buyurgan tarafta yazılmayan alan eksik, modeli izlemeyen alan bayat ölçülür; bildirimsel taraf aynı olaylarda uyumludur (10 uyumlu, 1 bayat, 1 eksik).
- Bozulma iki çerçevede de olur: bildirimsel ekranın modelde olmayan sabit metni artık verir (3 uyumlu, 1 artık).
- Uyum bir çerçeve seçim ölçütü değildir; seçim ekip, eski kod, platform sürümü ve özel çizim üzerinden düzyazıyla tartılır.
- Bu dersin uyumu: **uyumlu**.

## Kurs Kapanışı

Kurs, tek bir soruyla on beş dersi ölçtü: bu ekran modelle uyuşuyor mu? Her dersin olayı, uyumu ve sınırlayıcı ölçümü aşağıdadır. Uyum hücreleri kaynak dersin özetinden alınmıştır.

| Ders | Olay | Uyum | Sınırlayıcı ölçüm |
|---|---|---|---|
| Görünüm Denetleyicisi Kavramı | yükleme, okundu işareti, klasör değişimi, taslak gelişi, hücre yeniden kullanımı | dördü (3/2/2/2) | biçimlenmiş metin eşit sayılmaz; iki tarafta olmayan alan sayılmaz |
| Yaşam Döngüsü Yöntemleri | yalnız yüklemede yazılan değer, model altta değişir | bayat | çağrı sırasını model kurar, çerçeve değil |
| Gezinme Denetleyicileri | itme ve geri çıkarma, kalkan seçimin vurgusu | artık | çıkarılan ekran ölçüm dışı |
| Sunum Biçimleri | kip sunulan not, sunan ekranın yazmadığı alan | eksik | yalnız görünür ekrana bakılır |
| Görsel Düzenleyici ve Kodla Arayüz | kopuk bağlantı, yer tutucu metin | bayat | yer tutucu kodun yazmadığı etikette kalır |
| Bağlantılar ve Eylemler | modeli yazıp etiketi yazmayan eylem | bayat | biçimlenmiş metin ham değerle bayat çıkar |
| Kısıt Tabanlı Düzen | güncellenmeyen kısıt sabiti | bayat | öncelik ve belirsizlik modelde yok |
| Yığıt Görünümleri | gizlenmeyen alt görünüm | artık | gizleme ile kaldırma aynı değeri yazar |
| Tablo Görünümleri | yeniden kullanılan hücrede kalan ek | artık | kuyruk boyutu ölçülmez |
| Koleksiyon Görünümleri | eklenip bildirilmeyen öğe | eksik | konum hesabı ölçülmez |
| Temsilci Kalıbı | bağlanmamış temsilci | bayat | unutan kişi okunmaz |
| Çizim ve Katman Animasyonu | istenmeyen yeniden çizim | bayat | animasyon süresi ölçülmez |
| Bildirimsel ve Buyurgan Arayüz Bir Arada | atanmayan kök görünüm | bayat | bildirimsel yeniden hesap varsayım |
| Eski Kodun Kademeli Dönüşümü | taşınmayan alan, kalkan rozet | eksik | ekran düzeyinde tek yanıt yok |
| Çerçeve Seçimi | aynı model, unutulan alan | uyumlu | uyum seçim ölçütü değil |

Açılış dersi dışındaki on dört dersin dağılımı: 1 uyumlu, 7 bayat, 3 eksik, 3 artık. Çekirdeğin 3/2/2/2 dağılımı ayrı bir sayımdır: çekirdek açılış dersindeki dokuz alanı sayar, dağılım ise on dört dersin uyumunu sayar; ikisi aynı şey değildir.

Sıradaki kurs (M30/K05) verinin saklanmasını, ağ isteklerini ve eşzamanlılığı konu alır. Bu kursun ölçü ekseni orada sürmez; K05 kendi sorusunu kendisi sorar.
