- Published on
Yagona haqiqat manbai (single source of truth)
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
Yagona haqiqat manbai (single source of Truth)
Tasavvur qiling, turli xonalarda ikkita doska bor va ikkalasida ham bir xil uchrashuvlar jadvali yozilgan. Agar kimdir doskalardan birini yangilab, ikkinchisini shunday qoldirsa, ma'lumotlar bir-biriga zid bo'lib qoladi. Endi hech kim qaysi doskadagi ma'lumot to'g'ri ekanligiga amin bo'la olmaydi. Agar bir xil ma'lumot kodingizda ikki xil joyda alohida saqlansa, aynan shunday holat yuz beradi β ikkalasi ham "to'g'ri"dek ko'rinadi, lekin ular mos kelmaydi va natijada ilovangiz kutilmagan tarzda ishlaydi.
Ushbu bosqichda o'rgangan barcha narsalarimiz β @State, @Binding, @Observable va @Environment β bitta tamoyilga xizmat qiladi: har bir ma'lumot bo'lagi faqat bitta rasmiy egaga (owner), ya'ni u yashaydigan va vakolatli bo'lgan yagona joyga ega bo'lishi kerak. Unga muhtoj bo'lgan har qanday boshqa view esa o'zining shaxsiy nusxasini yaratmasdan, faqat o'sha yagona manbaga binding (bog'lanish) yoki ishora (reference) olishi kerak.
Ushbu darsning oxirida siz SwiftUI view ierarxiyasiga qarab holat to'g'ri boshqarilganligini aniqlashni, yagona haqiqat manbaini buzadigan keng tarqalgan xatolarni tanib olishni va buzilgan misolni to'g'ri ishlaydigan holatga keltirishni o'rganasiz.
To'g'ri ma'lumot egaligi qanday ko'rinadi
Mana o'sha data flow tuzilishi misoli:
| Dizayn qarori | Nima uchun bu to'g'ri tanlov |
|---|---|
Model RootView ichida yashaydi | RootView profil ma'lumotlariga muhtoj bo'lgan eng yuqori view hisoblanadi. Unga shu yerda egalik qilish barcha bolalar view'lariga bir xil nusxadan foydalanish imkonini beradi. |
HeaderView-da var profile | ProfileModel @Observable sinf (reference type) bo'lganligi sababli, uni oddiy o'zgaruvchi sifatida o'tkazish HeaderView-ga nusxa emas, balki obyektga ishora beradi. U qiymatlarni faqat o'qiydi va hech narsa yozmaydi, shuning uchun maxsus property wrapper kerak emas. |
EditView-da @Bindable var profile | @Bindable SwiftUI-ga ushbu @Observable obyekt xususiyatlariga binding-lar yaratishni bildiradi. Busiz TextField talab qiladigan $profile.name sintaksisi kompilyatsiya bo'lmaydi β chunki Swift oddiy o'zgaruvchidan binding-ni qanday olishni bilmaydi. |
EditView-da $profile.name | profile @Bindable deb belgilanganidan keyin, $ prefiksi o'sha aniq xususiyatga ikki tomonlama Binding yaratadi. TextField undan o'qiydi va unga yozadi β o'zgarish modelga yetib boradi va model HeaderView-ni avtomatik yangilaydi. |
Ushbu tamoyilni buzadigan pattern: Agar
EditViewo'zining shaxsiy@State private var localName = profile.nameo'zgaruvchisini yaratganida edi, u yaratilish (init) vaqtida qiymatdan shunchaki nusxa olib qo'ygan bo'lardi. Uni tahrirlashHeaderView-ni hech qachon yangilamasdi va ikkala view mutlaqo boshqa ma'lumotlarni ko'rsatib turardi. Bu eng ko'p uchraydigan xatodir va u har doim yagona haqiqat manbaini buzishga borib taqaladi.
Stage 2 uchun ma'lumotlar oqimi (data Flow) xulosasi
@State
Foydalanish: Faqat ushbu view-ga tegishli bo'lgan va boshqa joyda kerak bo'lmaydigan mahalliy UI holatlari uchun.
@State private var isExpanded = false
Holat uchun standart vosita. Agar ma'lumot faqat bitta view-ga kerak bo'lsa, uni @State sifatida saqlang. Murakkablashtirib yubormang β har bir qiymat uchun alohida model sinfi shart emas.
@Binding
Foydalanish: Bola view ota view-ga tegishli bo'lgan @State qiymatini o'zgartirishi kerak bo'lganda.
@Binding var isSelected: Bool
Bola view ota view egalik qiladigan qiymatni o'qishi va yozishi kerak bo'lsa, @Binding ishlating. Bu ma'lumot manbaini bitta joyda saqlagan holda bola view-ga unga kirish va yangilash imkonini beradi.
@Observable class + @State
Foydalanish: Ma'lumotlar murakkab bo'lganda, view-dan tashqarida saqlanishi kerak bo'lganda yoki bir nechta turli view-lar bir xil model nusxasidan foydalanishi kerak bo'lganda.
@Observable
class MyModel {
var data = ""
}
State-ni modelga ko'chiring (lift state), agar u view uchun juda murakkab bo'lsa, ko'plab bog'liq bo'lmagan view-lar unga muhtoj bo'lsa yoki biznes logikani interfeys kodidan ajratmoqchi bo'lsangiz.
@Environment
Foydalanish: Tizim qiymatlari (colorScheme, locale) yoki ilova miqyosidagi amallar (dismiss) har qanday joyda foydalanish uchun ochiq bo'lishi kerak bo'lganda.
@Environment(\.colorScheme) var colorScheme
Environment qiymatlarni daraxt bo'ylab qo'lda uzatmasdan hamma joyga ochiq qilish uchun xizmat qiladi. Tizim sozlamalari va kesishuvchi masalalar uchun ishlating. Undan oddiy ma'lumot egaligining o'rnini bosuvchi sifatida foydalanmang.
Tezkor ma'lumotnoma
| Vosita | Qachon ishlatiladi |
|---|---|
| @State | Ushbu view tomonidan boshqariladigan va boshqa joyda kerak bo'lmaydigan mahalliy UI holati |
| @Binding | Bola view ota view-ning @State qiymatini o'qishi va o'zgartirishi kerak bo'lganda |
| @Observable class + @State | Murakkab ma'lumotlar, bir nechta view-lar bitta model nusxasini baham ko'rganda |
| @Environment | Tizim tomonidan beriladigan qiymatlar yoki ilova miqyosidagi amallar |
| Oddiy o'zgaruvchi (var) | Ota-onadan keladigan faqat o'qish uchun mo'ljallangan ma'lumot β o'zgartirish talab etilmaydi |
| @Bindable | Bola view obyekt parametrini olganda va undagi xususiyatlarga binding ($) yaratishi kerak bo'lganda |
Topshiriq: xatolikni tuzatish (refactor the Bug)
Quyida keltirilgan noto'g'ri yozilgan ma'lumot oqimini tuzating. Sizda @State private var score = 0 saqlaydigan ParentView bor. U ScoreDisplayView va ScoreControlView view'larini yaratadi. Xatoligi bor versiyada ScoreControlView o'zining shaxsiy @State private var score = 0 o'zgaruvchisini e'lon qilgan va tugma bosilganda uni oshiradi β shuning uchun tugmani qancha bossangiz ham ScoreDisplayView har doim 0 ni ko'rsatib turaveradi. ScoreControlView-ni @Binding var score: Int ishlatadigan qilib qayta yozing (refactor qiling), ota view-ni esa $score o'tkazadigan qilib yangilang va ikkala view ham bir xil raqamni ko'rsatayotganini tekshiring. Bu topshiriq butun Stage 2 darslarining mohiyatini bitta xatolik yechimida ko'rsatib beradi.
Keyingi bosqichda siz Tartib va Joylashtirish (Layout in Depth) ni o'rganasiz β stack-lar, grid-lar, GeometryReader va har xil ekran o'lchamlari hamda yo'nalishlarida barqaror ishlash uchun layoutlar yaratish bo'yicha chuqur bilim olasiz.