Ders 20 / 21
Yerelleştirme
Yerel ayar ve yazı yönünün ortam tetiğiyle, modelin tarih özelliğinin gözlem tetiğiyle yeniden hesaplamaya yol açtığının ve biçimlemenin ölçülmediğinin gösterimi.
Yayın Güncelleme
Bu derste
- Yerelleştirmeyi metin, biçim ve yazı yönü olmak üzere üç ayrı konuya ayırır
- Yerel ayar ve yazı yönünün ortam değeri olarak okunduğunu ölçer
- Modelin tarih özelliğinin okuyan görünümü gözlem tetiğiyle yeniden hesaplattığını ölçer
- Biçimlemenin saf bir işlev olduğunu ve modelde yalnız yerel ayarı okuyan görünümün sayıldığını gösterir
İçindekiler
Önceki derste kullanıcının sistem tercihlerinin, onları okuyan görünümü ortam tetiğiyle yeniden hesaplattığını ölçtük. Kullanıcının dili ve bölgesi de aynı türden bir tercihtir. Soru yine aynıdır: bu yeniden hesaplamayı ne tetikledi? Bu derste bakılan tetik ortam; yanında bir gözlem örneği de vardır.
Yerelleştirme üç ayrı konuyu kapsar. Birincisi metin: arayüzdeki bir ifadenin kullanıcının diline çevrilmiş karşılığı gösterilir. İkincisi biçim: tarih, sayı ve para birimi kullanıcının bölgesinin alışkanlığına göre yazılır; aynı gün bir yerde gün-ay, başka bir yerde ay-gün sırasıyla görünür. Üçüncüsü yazı yönü: bazı diller sağdan sola yazılır ve arayüzün düzeni bu yöne göre aynalanır. Çerçeve ilk ikisi için yerel ayarı, üçüncüsü için yazı yönünü ortam değeri olarak sunar: @Environment(\.locale) ve @Environment(\.layoutDirection). Bu ikisi, önceki dersteki yazı boyutu gibi, görünümün dışından gelen 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)")
}
}
Yerel Ayar, Yazı Yönü ve Tarih
Aşağıdaki parça bir etkinlik ekranıdır. Etkinliğin başlangıç tarihi, gözlemlenebilir bir nesnede durur. Başlık yerel ayarı okur. Tarih etiketi hem tarihi hem yerel ayarı okur, çünkü tarihi o yerel ayara göre biçimler. Eylem satırı yazı yönünü okur ve bir ok işaretinin yönünü ona göre seçer. Alt not ise ham metindir; yerelleştirme ona uygulanmaz.
import SwiftUI
@Observable
final class EventStore {
var startDate = Date()
var title = ""
}
struct EventScreen: View {
let store: EventStore
var body: some View {
VStack {
EventHeader()
DateLabel(store: store)
ActionRow()
FooterNote()
}
}
}
struct EventHeader: View {
@Environment(\.locale) private var locale
var body: some View {
Text(locale.identifier)
}
}
struct DateLabel: View {
let store: EventStore
@Environment(\.locale) private var locale
var body: some View {
Text(store.startDate.formatted(.dateTime.day().month().locale(locale)))
}
}
struct ActionRow: View {
@Environment(\.layoutDirection) private var layoutDirection
var body: some View {
Text(layoutDirection == .rightToLeft ? "<" : ">")
}
}
struct FooterNote: View {
var body: some View {
Text(verbatim: "v1")
}
}
Bu parça derlenmez ve çıktı vermez; yalnız kaynak olarak durur. Okuma düzeni şöyledir. EventScreen doğrudan bir değer okumaz; yalnız çocukları kurar. EventHeader ve DateLabel yerel ayarı, DateLabel ayrıca store.startDate’i okur. ActionRow yazı yönünü okur. FooterNote hiçbir değer okumaz. Model, çerçevenin bağımlılık izleme kuralını kurar; çerçevenin kendisi değildir.
Üç değişiklik yazalım: kullanıcı dilini değiştiriyor, yazı yönü sağdan sola dönüyor ve etkinliğin tarihi değişiyor. Ortam değerlerini değiştirmek bu derste bir değiştirici değil, sistem ayarıdır.
// main.swift — yerel ayar, yazi yonu ve tarih
let storage: [String: Storage] = [
"startDate": .model(object: "EventStore"),
"locale": .environment,
"layoutDirection": .environment,
]
let screen = ViewTree(nodes: [
ViewNode("EventScreen", parent: nil, reads: []),
ViewNode("EventHeader", parent: "EventScreen", reads: ["locale"]),
ViewNode("DateLabel", parent: "EventScreen", reads: ["startDate", "locale"]),
ViewNode("ActionRow", parent: "EventScreen", reads: ["layoutDirection"]),
ViewNode("FooterNote", parent: "EventScreen", reads: []),
], storage: storage)
let recomputes = [
screen.change("dil-degisti", key: "locale"),
screen.change("yon-degisti", key: "layoutDirection"),
screen.change("tarih-degisti", key: "startDate"),
].flatMap { $0 }
countCauses(recomputes)
dil-degisti: locale degisti | yeniden EventHeader ortam, DateLabel ortam | atlanan EventScreen,ActionRow,FooterNote yon-degisti: layoutDirection degisti | yeniden ActionRow ortam | atlanan EventScreen,EventHeader,DateLabel,FooterNote tarih-degisti: startDate degisti | yeniden DateLabel gozlem | atlanan EventScreen,EventHeader,ActionRow,FooterNote yerel: 0 ebeveyn: 0 gozlem: 1 ortam: 3
Dil değişince yerel ayarı okuyan iki görünüm, başlık ve tarih etiketi, ortam tetiğiyle yeniden hesaplanır. Ekran, eylem satırı ve alt not atlanır. Yazı yönü değişince yalnız eylem satırı yeniden hesaplanır. Tarih değişince ise yalnız tarih etiketi hesaplanır ve tetik gözlemdir: tarih, bir model nesnesinin özelliğidir. Aynı etiket, hem ortamdan hem modelden değer okuduğu için iki ayrı kanaldan yeniden hesaplanabilir; hangi kanalın çalıştığını, değişen anahtar belirler.
Son sayım üç ortam ve bir gözlem yeniden hesaplamasını verir. Yerel ve ebeveyn sayıları sıfırdır, çünkü bu ağaçta hiçbir görünüm bir üst görünümden değişen bir değer almaz ve bir yerel durum değişmez. Ortam sayısının ağırlığı, yerelleştirmenin sistem tercihlerine dayanmasından gelir.
EK17. Bu ölçüm yalnız DateLabel’ın yerel ayarı açıkça @Environment ile okuduğu ağaç için geçerlidir. Metin sabitlerinin çerçeve tarafından yerel ayara göre çözümlenmesi ayrı bir iştir ve ağaçta okuma olarak yazılmadı.
EK18. Bu ölçüm yerel ayarın değiştiği anı tek bir etiketle temsil eder. Dil değişince uygulamanın yeniden başlatılıp başlatılmadığı ölçülmedi.
Yazı Yönü Neyi Değiştirir
Sağdan sola yazılan bir dilde arayüzün düzeni aynalanır: satırın başı sağda olur, ilerleme ve geri okları yön değiştirir. Çerçeve bunu yığıtlar ve listeler gibi kapsayıcılarla kendisi yapar; ama ok işareti gibi yöne bağlı içerik görünümün kendi kararıdır ve bu karar için layoutDirection ortam değeri okunur. Yön değişince bu değeri okuyan görünüm yeniden hesaplanır.
Burada iki tür yön bağımlılığı karışmamalıdır. Çerçevenin aynalamasını kendisi uyguladığı kısım, görünümün bir değer okumasını gerektirmez. Görünümün kendi içeriğini yöne göre seçmesi ise bir okuma ve dolayısıyla bir bağımlılıktır. Ölçüm yalnız ikincisini sayar. İlkinin ağaçta hangi görünümleri hesaplattığı çerçevenin iç işidir ve ölçülmedi.
EK19. Bu ölçüm yazı yönünün iki değerinden yalnız birinin değişimini temsil eder. Aynalanan düzenin ölçüleri, hizalama ve görünüm sırası ölçülmedi.
EK20. Bu ölçüm tarih etiketinin ekranda hangi biçimde yazıldığını söylemez. Tarihin yazılışı ölçülmedi.
Sınırlayıcı Ölçüm
Biçimleme, bir değerin ve bir yerel ayarın girdi olduğu bir işlevdir: bu derste kurulan işlevde aynı değer ve aynı yerel ayar her zaman aynı metni verir. Gerçek takvim biçimlemesi yerel ayarın yanında takvime ve saat dilimine de bağlıdır; bunlar ölçülmedi. Bu işlev bir yeniden hesaplamanın nedeni değildir; neden, işleve girdi olan yerel ayarın değişmesidir. Gerçek tarih ve sayı biçimleri yerel ayar verisine dayanır ve bu veri aygıta bağlıdır, bu yüzden bu derste ölçülmez. Aşağıdaki blok, biçimlemenin bir işlev olduğunu küçük bir örnekle gösterir ve ardından modelin yalnız yerel ayarı okuyan görünümü saydığını sınar.
// main.swift — bicimleme saf bir islevdir
func dayLabel(day: Int, month: Int, monthFirst: Bool) -> String {
monthFirst ? "\(month)/\(day)" : "\(day).\(month)"
}
print(dayLabel(day: 5, month: 3, monthFirst: false))
print(dayLabel(day: 5, month: 3, monthFirst: true))
let storage: [String: Storage] = [
"locale": .environment,
]
let screen = ViewTree(nodes: [
ViewNode("DateLabel", parent: nil, reads: ["locale"]),
ViewNode("FooterNote", parent: nil, reads: []),
], storage: storage)
let recomputes = screen.change("yerel-ayar-degisti", key: "locale")
print(recomputes.count)
5.3 3/5 yerel-ayar-degisti: locale degisti | yeniden DateLabel ortam | atlanan FooterNote 1
İlk iki satır aynı günün iki sırayla yazılışıdır; bu gerçek bir yerel ayar biçimi değil, yalnız bir saf işlev örneğidir. Gerçek bir takvim biçiminin çıktısı ölçülmedi. Üçüncü satır, modelin yalnız yerel ayarı okuyan görünümü saydığını gösterir: DateLabel ortam tetiğiyle yeniden hesaplanır, FooterNote atlanır. Biçimleme işlevinin kendisi bir görünüm değildir ve ağaçta yer almaz; son satırdaki 1, yeniden hesaplanan görünüm sayısıdır.
Özet
- Yerelleştirme metin, biçim ve yazı yönünü kapsar; çerçeve bunlar için yerel ayarı ve yazı yönünü ortam değeri olarak sunar.
- Yerel ayar ya da yazı yönü değişince yalnız o değeri okuyan görünüm ortam tetiğiyle yeniden hesaplanır.
- Modelin tarih özelliği, onu okuyan görünümü gözlem tetiğiyle yeniden hesaplatır; aynı görünüm hem ortam hem gözlem kanalından hesaplanabilir.
- Biçimleme saf bir işlevdir; ağaçta yer almaz ve yalnız yerel ayarı okuyan görünüm sayılır.
- Bu dersin tetiği: ortam.
Sonraki Adım
Bu konunun son dersi, bu tetiklerin hızlı bir geri bildirim döngüsüyle nasıl görüldüğüne bakar. Ön izleme, bir görünümü örnek bir modelle çalıştırır; hangi örnek modelin verildiği, yukarıda ölçtüğümüz değerlerden hangilerinin ön izlemede değişebildiğini belirler. Sonraki derste ön izlemenin örnek model enjeksiyonunu ve yinelemeyi ele alacağız.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.