Ders 21 / 21
Ön İzleme ve Yineleme
Ön izlemenin örnek modeli ve ezilen ortamıyla bir görünümü nasıl yeniden hesaplattığının, ön izlemenin açılışının ise neden değişiklik sayılmadığının gösterimi ve kursun yirmi bir derslik özeti.
Yayın Güncelleme
Bu derste
- Ön izlemenin bir görünüme örnek model ve ezilmiş ortam verdiğini açıklar
- Örnek modelin özelliği değişince okuyan görünümün gözlem tetiğiyle yeniden hesaplandığını ölçer
- Ön izlemenin açılışının bir değişiklik değil yeni bir başlangıç durumu olduğunu gösterir
- Kurstaki yirmi bir dersin tetik dağılımını tabloda okur
İçindekiler
Önceki derste yerel ayarın ve yazı yönünün ortam tetiğiyle yeniden hesaplamaya yol açtığını ölçtük. Bu derste hızlı geri bildirim döngüsüne bakıyoruz: bir görünümü uygulamanın tamamını çalıştırmadan, tek başına ekranda görmek. Soru yine aynıdır: bu yeniden hesaplamayı ne tetikledi? Bu derste bakılan tetik gözlem.
Ön izleme, bir görünümü kendi başına kurar. Görünüm bir modele ihtiyaç duyuyorsa ön izleme ona gerçek veri yerine bir örnek model verir. Görünümün okuduğu ortam değerlerini de ön izleme belirleyebilir; örneğin koyu renk şemasını zorlayabilir. Bu iki yol, daha önce ölçtüğümüz iki tetiğe denk gelir: örnek modelin özelliği gözlem, ezilen ortam değeri ortam tetiğidir. Ön izlemenin kendisi bir geliştirme aracının işidir ve bu derste ölçülmez; ölçülen, ön izlemenin görünüme verdiği değerlerdir.
Ölçüm çekirdek dosyayla yapılır; çekirdek her derste aynı dosya adıyla ve aynı içerikle gelir.
// 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)")
}
}
Örnek Model ve Ezilen Ortam
Aşağıdaki parça bir profil ekranıdır. Ad ve durum, gözlemlenen bir modelin özellikleridir. Avatar renk şemasını ortamdan okur. İki ön izleme bildirimi aynı ekranı farklı biçimde kurar: biri modele kısa bir ad yazar, öteki renk şemasını koyuya çevirir.
import SwiftUI
@Observable
final class ProfileStore {
var displayName = ""
var status = ""
}
struct ProfileScreen: View {
let store: ProfileStore
var body: some View {
VStack {
AvatarView()
NameLabel(store: store)
StatusBadge(store: store)
}
}
}
struct AvatarView: View {
@Environment(\.colorScheme) private var colorScheme
var body: some View {
Circle().fill(colorScheme == .dark ? Color.white : Color.black)
}
}
struct NameLabel: View {
let store: ProfileStore
var body: some View {
Text(store.displayName)
}
}
struct StatusBadge: View {
let store: ProfileStore
var body: some View {
Text(store.status)
}
}
#Preview("Short name") {
let store = ProfileStore()
store.displayName = "Ada"
return ProfileScreen(store: store)
}
#Preview("Dark") {
ProfileScreen(store: ProfileStore())
.environment(\.colorScheme, .dark)
}
Bu parça derlenmez ve çıktı vermez; yalnız kaynak olarak durur. Okuma düzeni şöyledir. ProfileScreen doğrudan bir değer okumaz; modeli çocuklara iletir ama özelliklerine dokunmaz. NameLabel displayName’i, StatusBadge status’u, AvatarView ise colorScheme’i okur.
Üç değişiklik yazalım. İlk ikisi örnek modelin özellikleridir: ad ve durum. Üçüncüsü, ön izlemenin ezdiği renk şemasının değişmesidir.
// main.swift — ornek model ve ezilen ortam
let storage: [String: Storage] = [
"displayName": .model(object: "ProfileStore"),
"status": .model(object: "ProfileStore"),
"colorScheme": .environment,
]
let preview = ViewTree(nodes: [
ViewNode("ProfileScreen", parent: nil, reads: []),
ViewNode("AvatarView", parent: "ProfileScreen", reads: ["colorScheme"]),
ViewNode("NameLabel", parent: "ProfileScreen", reads: ["displayName"]),
ViewNode("StatusBadge", parent: "ProfileScreen", reads: ["status"]),
], storage: storage)
let recomputes = [
preview.change("ornek-ad-degisti", key: "displayName"),
preview.change("ornek-durum-degisti", key: "status"),
preview.change("ezilen-kip-degisti", key: "colorScheme"),
].flatMap { $0 }
countCauses(recomputes)
ornek-ad-degisti: displayName degisti | yeniden NameLabel gozlem | atlanan ProfileScreen,AvatarView,StatusBadge ornek-durum-degisti: status degisti | yeniden StatusBadge gozlem | atlanan ProfileScreen,AvatarView,NameLabel ezilen-kip-degisti: colorScheme degisti | yeniden AvatarView ortam | atlanan ProfileScreen,NameLabel,StatusBadge yerel: 0 ebeveyn: 0 gozlem: 2 ortam: 1
Örnek modelin adı değişince yalnız NameLabel yeniden hesaplanır ve tetik gözlemdir. Durum değişince yalnız StatusBadge hesaplanır. Ezilen renk şeması değişince yalnız AvatarView hesaplanır ve tetik ortamdır. ProfileScreen üç değişiklikte de atlanır, çünkü modeli yalnız iletir, hiçbir özelliğini okumaz. Son sayım iki gözlem ve bir ortam yeniden hesaplamasını verir; yerel ve ebeveyn sayıları sıfırdır, çünkü ağaçta bir durum sahibi ya da değer ileten üst görünüm yoktur.
Bu dersin ana ölçümü budur: ön izleme görünüme gerçek bir kaynaktan değil, kendi örnek modelinden değer verir; bu değer değişince görünüm, çalışan uygulamadaki gibi bağımlılık kuralına uyar. Bu yüzden bir görünümün hangi özellikleri okuduğunu ön izlemede görmek, o görünümün hangi değişiklikte yeniden hesaplanacağını görmenin ucuz bir yoludur.
EK21. Bu ölçüm örnek modeli iki özellikli bir nesne olarak ele alır. Gerçek bir modelin koleksiyonları ve iç içe nesneleri ölçülmedi.
EK22. Bu ölçüm ön izlemenin renk şemasını ezmesini, tek bir ortam anahtarının değişimiyle temsil eder. Ön izlemenin aynı anda birden çok ortam değerini ezmesi ölçülmedi.
Yineleme ve Geri Bildirim
Yineleme, kodu değiştirip sonucu yeniden görmektir. Ön izleme bu döngüyü kısaltır, çünkü görünümü yalnız kendi örnek verisiyle kurar. Burada iki ayrı şey karışmamalıdır. Görünümün kaynağını değiştirmek, ön izlemenin yeniden kurulmasına yol açabilir. Örnek modelin bir özelliğini değiştirmek ise çalışan bir görünümün yeniden hesaplanmasına yol açar. İlki bir kod değişikliğidir ve modelin konusu değildir; ikincisi bu kursun boyunca ölçtüğümüz türdendir.
Bunun pratik sonucu şudur. Bir görünüm ön izlemede beklenmedik sıklıkta yeniden hesaplanıyorsa, nedenini şu dört sorudan biriyle ararız: değer görünümün yerel durumu mu, ebeveynin ilettiği bir değer mi, bir modelin özelliği mi, yoksa ortamdan gelen bir değer mi? Ön izleme bu soruyu yanıtlamaz, ama yanıtı denemek için hızlı bir ortam sağlar.
EK23. Bu ölçüm yineleme döngüsünün süresini hiçbir biçimde temsil etmez. Ön izlemenin ne kadar hızlı yenilendiği ölçülmedi.
EK24. Bu ölçüm ön izlemenin kaynaktan yeniden kurulmasını bir değişiklik olarak saymaz. Kaynak düzenlemelerinin ağaca etkisi ölçülmedi.
Sınırlayıcı Ölçüm
Ön izlemenin açılışı bir değişiklik değildir; yeni bir başlangıç durumudur. Her ön izleme ağacı baştan kurar. Model bunu yeni bir ViewTree olarak kurar ve yeniden hesaplama saymaz. Aşağıdaki blokta aynı görünümler için iki ön izleme kuruyoruz. Birinin açılışı hiçbir kayıt bırakmaz. Değişiklik yalnız birinde yapılır ve ötekini etkilemez.
// main.swift — onizleme yeni bir baslangic durumudur
let storage: [String: Storage] = [
"displayName": .model(object: "ProfileStore"),
]
let nodes = [
ViewNode("ProfileScreen", parent: nil, reads: []),
ViewNode("NameLabel", parent: "ProfileScreen", reads: ["displayName"]),
]
let first = ViewTree(nodes: nodes, storage: storage)
let second = ViewTree(nodes: nodes, storage: storage)
let firstRun = first.change("ornek-ad-degisti", key: "displayName")
print(firstRun.count)
print(second.nodes.count)
ornek-ad-degisti: displayName degisti | yeniden NameLabel gozlem | atlanan ProfileScreen 1 2
Kurulumun kayıt bırakmaması kodun kendisinden okunur: ViewTree başlatıcısı yalnız düğümleri ve depolama tablosunu saklar, yeniden hesaplama ise yalnız change çağrısıyla üretilir. İlk satır, değişikliğin ilk ağaçta yalnız NameLabel’ı yeniden hesaplattığını, ProfileScreen’i atladığını söyler; ikinci satır bu yeniden hesaplamaların sayısı olan 1’dir. Üçüncü satır ikinci ağacın baştan kurulmuş, iki düğümlü, değişmemiş bir ağaç olduğunu gösterir: bir ön izlemedeki değişiklik öteki ön izlemeye yansımaz.
Kurs Kapanışı
Kurs boyunca yirmi bir ders, her biri bir yeniden hesaplamanın nedenini ölçtü. Aşağıdaki tablo her dersin ölçtüğü değişikliği, dersin tetiğini ve sınırlayıcı ölçümün neyi ölçemediğini gösterir.
| Ders | Değişiklik | Tetik | Sınırlayıcı ölçüm |
|---|---|---|---|
| Bildirimsel Sözdizim | altı değişiklik | dördü (2/2/2/2) | saklanmayan değer tetik üretmez |
| Görünümler ve Değiştiriciler | yazı tipi değişti | ortam | kendi yazı tipini koyan çocuk ortamı okumaz |
| Yığıt Düzenleri | aralık değişti | ebeveyn | kardeş katman değeri okuyamaz |
| Düzen Sistemi | kompakt oldu | ebeveyn | önerilen genişlik ölçüm dışı |
| Izgara ve Geometri | sınıf değişti | ortam | okuyucunun boyutu ölçüm dışı |
| Listeler ve Formlar | başlık değişti | gözlem | tek satır öteki satırları atlatır |
| Görsel Bileşenler | renk şeması değişti | ortam | statik görsel değer okumaz |
| Görünüm Kurucular | başlık değişti | ebeveyn | kapanış ağaçta düğüm değildir |
| Yerel Durum | dokunuldu | yerel | kardeşin durumu okunamaz |
| Bağlama | çocuk yazdı | ebeveyn | kural yazanı okumaz |
| Gözlemlenebilir Nesneler | kitap eklendi | gözlem | nesne düzeyi bildirim daha geniştir |
| Ortam Değerleri | kip değişti | ortam | ezme tek kayıtla ölçülmez |
| Gezinme Yığıtı ve Yolu | ekran itildi | yerel | itilen hedef yeni düğümdür |
| Sunum ve Kapatma | sayfa açıldı | yerel | kapatma eylemi değer değildir |
| Sekme ve Araç Çubuğu | arşive geçildi | yerel | seçilmeyen sekme atlanır |
| Hareketler | sürükleme bitti | yerel | sürükleme hızı saklanmaz |
| Örtük ve Açık Animasyonlar | panel açıldı | yerel | animasyon farkı ölçülmez |
| Geçişler | ileti silindi | gözlem | kalkan görünüm ağaçta yoktur |
| Erişilebilirlik | yazı büyüdü | ortam | sabit etiket değer okumaz |
| Yerelleştirme | dil değişti | ortam | biçimleme saf işlevdir |
| Ön İzleme ve Yineleme | örnek ad değişti | gözlem | ön izleme yeni başlangıçtır |
Açılış dersi dışındaki yirmi dersin tetik dağılımı şöyledir: yerel 6, ebeveyn 4, gözlem 4, ortam 6. Açılış dersinin çekirdeği ayrıca 2/2/2/2 dağılımını verdi. İkisi aynı şey değildir: çekirdek sekiz yeniden hesaplama sayar, dağılım ise açılış dışındaki yirmi dersin tetiğini sayar.
Özet
- Ön izleme bir görünüme örnek bir model ve gerekirse ezilmiş ortam değerleri verir; ölçülen, bu değerlerdir.
- Örnek modelin bir özelliği değişince onu okuyan görünüm gözlem tetiğiyle yeniden hesaplanır.
- Ön izlemenin ezdiği ortam değeri değişince onu okuyan görünüm ortam tetiğiyle yeniden hesaplanır.
- Ön izlemenin açılışı bir değişiklik değil yeni bir başlangıç durumudur; ağaç baştan kurulur ve yeniden hesaplama sayılmaz.
- Yirmi bir dersin her biri bir tetiği ölçtü; sınırlayıcı ölçümler modelin neyi ölçemediğini gösterdi.
- Bu dersin tetiği: gözlem.
Sonraki Adım
Bu kurs, bildirimsel bir arayüzün neden yeniden hesaplandığını ölçmekle bitti. Sıradaki kurs konu alanını değiştirecek: buyurgan arayüz çerçevesiyle yazılmış bir ekranı kavrayacak ve ikisi arasında köprü kuracağız. Bu kursta öğrendiğimiz soru ve dört tetik, o köprünün iki yanını karşılaştırırken dayanacağımız dil olacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.