Ders 05 / 21
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ü.
Yayın Güncelleme
Bu derste
- 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
İçindekiler
Ö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.
// 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.
// 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.
// 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.
// 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.
// 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.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.