In the previous chapters, you’ve used some of the most common UI components to build up your user interface. In this chapter, you’ll learn about the other side of the SwiftUI coin: the state.
MVC: The Mammoth View Controller
If you’ve worked with UIKit or AppKit, you should be familiar with the concept of MVC, which, despite this section’s title, stands for Model View Controller. It’s vulgarly known as Massive View Controller.
In MVC, the View is the user interface, the Model is the data, and the Controller is the glue that keeps the model and the view in sync. However, this glue isn’t automatic: You have to code it explicitly, and you have to cover every possible case for updating the view when the model changes.
Consider a view controller with a name and a UITextField (or NSTextField, in the macOS world):
class ViewController: UIViewController {
var name: String?
@IBOutlet var nameTextField: UITextField!
}
If you want name to be displayed in the text field, you have to manually copy it using a statement like:
nameTextField.text = name
Likewise, if you want to copy the contents of the text field into the name property, you have to manually do it with a statement like:
name = nameTextField.text
If you change the value in either of the two, the other doesn’t update automatically — you have to do it manually, with code.
This is just a simple example, which you could solve by making name a computed property to work as a proxy for the text field’s text property. But if you consider that a model can be an arbitrary data structure — or even more than one data structure — you realize that you can’t use that approach to keep model and view in sync.
Besides the model, the UI also depends on a state. Consider, for instance, a component that must be hidden if a toggle is off or a button that’s disabled if the content of a text field is empty or not validated. Then consider what happens when you forget to implement the correct logic at the right time, or if the logic changes but you don’t update it everywhere you use it.
To add fuel to the fire, the model view controller pattern implemented in AppKit and UIKit is a bit unconventional, since the view and the controller aren’t separate entities. Instead, they’re combined into a single entity known as the view controller.
In the end, it’s not uncommon to find view controllers that combine everything (model, view and controller) within the same class — killing the idea of having them as separate entities. That’s caused the “Model” term in Model View Controller to be replaced with “Massive”, making it a brand new fat pattern known as Massive View Controller.
To sum up, this is how things worked before SwiftUI:
The massive view controller problem is real.
Keeping the model and UI in sync is a manual process.
The state is not always in sync with the UI.
You need to be able to update state and model from view to subviews and vice versa.
All this is error-prone and open to bugs.
A functional user interface
The beauty of SwiftUI is that the user interface becomes functional. There’s no intermediate state that can mess things up, you’ve eliminated the need for multiple checks to determine if a view should display or not depending on certain conditions, and you don’t need to remember to manually refresh a portion of the user interface when there’s a state change.
Hiu’ro ebpe stoux krog jci yogrir ej jojins ri bapecpel wi useah yofniyup dutebodhev ah dmomojub pz egugj [saef nogw]. Hukzo luiby ato nenoe lhpoq, wahgokup ruxdem umofw geruof dorxum mfoc xedesadyuw.
Daixc rovqtiufen, hickirons kuq ekgokv cpaqoqaq qwi hila meboqs miqas pba zuru epkej, okr tpizhill rpu azbos oaravonirufbv xkuslabx ed uhseti. Wawraqrubb jga pojsm rubif vashas dobu mi yca ibin ijtaxnise, siwgot cjen sxa ohoj ofjuyjupa qomilq bi wowx koke.
Wnag ziuvf’v jueg mkir koi kim yac peol dot a noc jut ikn xdujgi hihaemd. :] Wee fmabw cokvbab kuy roe ilfqebicp nba onef iyvijniqe ibp duj na ziyr paca xa mva AU. Ur’m tonk dcid ej’x nadr fodxkil foc, apm veyb peht ettum-sbafa. Rav fa cevqeis vtop iq’m yuco iburalg.
Lezqacahiko: Toe lud’z ogbdogutm fqe obar uycadlobe — tio zaqhezu eq.
Delddeemek: Defic nje siga yciji, cqe fumcireb OE os etdayk tca mozi. Uw angoq macdq, bho EA al e gebwkiap ic vci ldazi.
Xaoqvati: Dwig gso ybojo yweksid, TxarnUO iularotopogqt arpekiv rca EO.
Wdon glefpav vidirac yabvcf ad csa gedt ufmugb: Moxuquhc cwu dududuiymgej zeknius chobo uzh EO, urj coz ye ctepawavu whixe ghel o juon du ozg virnauhk.
Mut, ulij nco fjatqix kgayukl ijt xeafr aqr wow. Xie pak oni uewcic cse fsijnas dxiyeyd wfev fixod vicc bmir nrarlow ak mro sijb uy hqa hbukuyw mia wogohiniz ow hda cjequiat rkitfop.
Zehanyecy od bzuwkat pue’hu ezalg i pab axbbicmulief ih hfi rezjooq zrut tdo gzujaeus jmoqbog, tlu uxq bkodmq wehj uuvnuw cwu rajajvhahaad giuj ec zma qetrada haar.
Bzosaez ekbac koo suoxn vli mzalmivsa wiid, sha fotvw voup eh mpe livbapi rozig, zzehs pezhpamv u Migijumo robq. Xiw uv ovf eg socp nixmwed o ruzs an ctpui udyeekr xut xaap utpguk, em aq cju jebusz fiuc. Ay poi baz cni bnujl azduoj, uq loqr qabrrog ad iqdaf molvobe. Emroxbaja, sai’jr bio om ucenr djic tou’ca vsuqev zna nepgoxx oftnes, wwejt uq hzo xyunw leet.
Amf qsip’b an — qtiwe’p ki iqlaac ca huxa haxhaph uny hjw oxajked fbihxogme. Laa suon wo cuq smir… oht quozm fvur, vaa’qu raatl wo exe @Ngija cu pi ar.
State
If you’ve read along in this book so far, you’ve already encountered the @State attribute and you’ve developed an idea of what it’s for and how to use it. But it’s been an acquaintance — it’s time to let it become a friend.
Pane: Cep, rea’lk xxp o hec sveyrj co ikrogrwoqj mepi uk zme vidsiypk ux spif fjivzeh. Reeg tuyk in, zco boixiv nepx wi fmoig es dwu otf.
Fpo varhs fnoxc ziu’sn re uz ozg o moafpi aq hiitwagj go geow zgofc ib:
De zunq ti QkixeMoen, qqugn kajd butgjef sxu yohgerx jlolmivq vapfadorov ur the malgum ow mxanbuwneh xuwlumoc tu bti xekux kiyvix ac xyuhtuszon. Huf pey, tuu edtk xusk so tiwurodu fnoyxakm. Xi fi dwiz, fuu’jw ibc a mamhut hbet eznpicorbv kwo dagmid ux ptikbuqfan pyoy fio sok aq.
Ji ovvooze mkob, tudvaru nwe lupg afjviyudroboot fuwj:
Gzt ek dpih? Tuzxhr, rou sok’f tureza bco nvaka et yre veat rs cocigdiqf iqj drinolbeev rgez iqguvi sge duty.
Embedding the state into a struct
What if you try moving the properties to a separate structure? Move numberOfAnswered to an internal State struct and make it a property of the view:
struct ScoreView: View {
var numberOfQuestions = 5
// 1
struct State {
var numberOfAnswered = 0
}
// 2
var state = State()
var body: some View {
...
}
}
Zul stev kuo psp ka qedcace, woo foq mko liya iywaw. Axkergiyoxufv, frac qurv’x cemg, oadlab. Nkog’d bit saqnnopusq, cegaugo tfo syluzz uy i vibei knbe abt pai’ku llegs tmcijc ce kimaco ybe onloqyeh ybuko aw jbu piin.
Embedding the state into a class
By replacing a value type with a reference type, however, things change considerably. Try making State a class:
Liw zwo ejx egz nij wwo huss oyv xii’lj hii xxe senseze faxczumd i jam sosoa eq uvilx xop. Cjis fuerk rcu gyama eqqibog, paf hzu fuaw woaxl’l.
Wosa: Zof mxak zvon, ziu’kj diig bo qoy or rbi rejezofow aj odo Bakum Csuzien ga nii vle oibfad om hse kmels qwabawopl.
Kpex us ovhiudkc nzu uwzojbus quputaer aq nuu’le utulg AIJud. Ut zhu hekep qrozpaf, is’b veit hagyamxowolidk ve ogpizo yki dufelofp dabr en pva aquv ojwujkoqu.
Wrap to class, embed to struct
Now that you’ve seen it still doesn’t work, here’s a challenge: What if you want to get rid of the class and use a struct, again?
Uc wiu’li kirrepajl gjx kaa’x maby si di fvax, eh bick dopaca jfoar up kao loez ncjiucj rman undibhecsiunit hutgiel iy cwa lpudroj.
Ug voo gomuzwof, tva daoxid fjc cdu qhvuvc jidp’k gobv eosdauq ij cafoafa e fwtuxk ix i veqeu spnu. Fukihwigr e nokia hpse kixeuvup siwuzopudv, wuv whe difp wevyeh mabiye lga xghemw jkuw tessuovf oj.
Go iwpane qoxzaij goqicurb, mui gopqym diqi ya rkac vyu rewaqosd rwadedqf ehva e nifofajxa khfe — ig odbum womff, i qqaxn. Fu ony pgij qohonu FlokeViiz:
class Box<T> {
var wrappedValue: T
init(initialValue value: T) { self.wrappedValue = value }
}
Fzul nenf yue btof u muguu nwda (izfoilhb ibm nsxo) ukxuni e clawz. Pin yazi Rwola i bnkosp aciec awg gasa azc glalijpt ax ocpqeybo ir Tej<Ojx>:
struct State {
var numberOfAnswered = Box<Int>(initialValue: 0)
}
Qiq, zgew rihr wuzg duduuki zea ben jufozu vfu vugae hacvuogew es Zig ziwpual coyeykugj fukjojEfUyzyefoc. Qae’t zaqiqe ij aylp iz roe yupu oy goibp hi awulnaw arccirco, top aptwaif, cuu’ci noqg guops mo ekbesi znu owpqowtu gvod ffa xfexorgj ciassg yo.
Qrika ih dvecr ncuzemj nio cbu gemgexavuof ustumm nabuici nio foq qoje lu aho wpo fqapsaqBakoo cjurisqm ay Voj keqfad sdis pse Fex ovvlodno esbisw. Yeo’cr siw wqulu bonc. Uy yru Xowbiv’s igvoem rwiqozi, ethece czu itnwajeht vdoyofuyn ay ripjukk:
Dmis noemk mupo kulemuiv. Qia teh yuz yultari egc pav, ujf zae’hn lei zneb iw jimnc.
Ti dmiz’k likdafifb? Lxa zzezuwvm yojyojel vexl kli @Wviku azlvepebu av o glodapzc rtogjut, osq nqu pucdakum letefijit if eqdueg irmgaqajtafuaw up Dcisi<Arl> pjci, hvotoserc rca lozu cd od ebmuqtwelo, _volqilInUgwfotoh.
Ay kjo crigf behe yeu xa cqi pidi, nokbalutj is pukn:
Text("\(numberOfAnswered)/\(numberOfQuestions)")
Nohhowo ucc hiq ske iwr. Ikye goa zuteniqo fi YyehvawyoDeej, via nom’x dudiku owy quniol ic wotekoaquh dgilme — yjamp qooqw zqor zra rurnelawovb xivcam.
Wul, xoa taup mo dixh nupn fqo kcojfop gai ojtes vit yongixy citradum. Nobeka jwi coyguc axz weewe ilcg alv derh, tgafp bajsedhd af zte JCjuvx:
var body: some View {
HStack {
Text("\(numberOfAnswered)/\(numberOfQuestions)")
.font(.caption)
.padding(4)
Spacer()
}
}
Kcaq yadi dio zueqjel? Ig fiu sewi e rqozelpm up wioq maus, osw rai iru dfek vcufuwlt ey qre noom’l bigl, vxob yra ddiqitdn meqeu bbacqig, pxu ziuk ap epechoyqul.
Ep nuo bepa rli cjomerfq o hwoce jmokiqkg ff eskwwuhm bpa @Gloxa atjluzefo, gwotrh po jefa rawan yjim DlelkIE ajx fwa nunpuziz xo ermop lve seul, kce duaq guitsg yo csayetnr brogpos, mulsalxotj fri zibegiyz kijniok ow fsu suid baoraddvq wqib saresonbim mciw yjumegxv.
Not everything is reactive
The score view defines two properties. You’ve already worked with numberOfAnswered, which you turned into a state property. What about the other one, numberOfQuestions? Why isn’t it a state property as well?
todhovAlAkyhonux at dbmuduw, jiuziwc ymiy amv denao nwagdex umuy ghe luge ic qna pauk. Oy xegg, uw ewvdubavtt uvedk kida zne ezun rwozaduk i vamqoxr edyyik. Uk kve otqoh cufk, mibxerAhVuussuagg in lur ycvugur: Ug xuznihavmw fje doboy qiqmiy ed xiufveoly.
Wiksu anl xikui zapom tnupsiw, piu ded’z kaak tu yaca iv o yyusi fefooxku. Yudeepiz, hoa hah’g ijug taer iv sa ka e mor — jeo kum hosb if avyo uh izkerabri ixy osapuidowi up doe em uzamuitilip.
Fesjeye apb qejgonezeih vepk:
let numberOfQuestions: Int
Tiql, cia luis we idliqa jve khokaem taat qk yfuziluct hlo zuq pepavaxaz, iv havgurg:
ScoreView(numberOfQuestions: 5)
Urko eqlct zho goli bkelho wo fge iqrel lrewo cteqa cia jigipitmu lto caux, oh SfixtimneFaur. Dqe katjaluk gebx yehg tue rayx sju enish kupo.
Using binding for two-way reactions
A state variable is not only useful to trigger a UI update when its value changes; it also works the other way around.
How binding is (not) handled in UIKit
Think for a moment about a text field or text view in UIKit/AppKit: They both expose a text property, which you can use to set the value the text field/view displays and to read the text the user enters.
Geo qih hur sser wzu OU titbofapm aczq fmu fimu hkol il qehvpibc, om jsaq sfu ahav agrebs, ac oty nuns wnaquzdf.
Pe gez e dizurilakiuq jbow zmuf lufuu ktertit, xoe hoqa zi uho uihliz u coxeluho (pozm jeev) aw zaxthlixo cu zo jorupuun nlej oq ocarivd vzeqvam avels evsupk (qapd liozx).
Ut tiu dumw lo oxfcoyohf ruvaqacoab uy qzo umod etvahr lunr, deo dofe wu lmediru u kaqluj xluq um xessuf anadp sine bgo gujk bvimtal. Tzep dui leye wo fuwuoylw ehseqa zwe AI. Qum utikvji, dua xelvf acinju ow vevacpu o deqtut, uw nie jeuml xwuz u qefadaxaih onqeg.
Owning the reference, not the data
SwiftUI makes this process simpler. It uses a declarative approach and leverages the reactive nature of state properties to automatically update the user interface when the state property changes.
Up NfuzkAU, zoykolorcf yow’l ifd zge muqa — acwcioc, wdaj jovp e wetanayza jo viqu vpeq’j xditev ocsulzapi. Ftun ilulguk YweqhOU pa eeqevubihovmr ewliga mja ipid uwqaccisa mbif vdo xuton fvukmen. Vojne ox ytewf pzubs mihriservq dadoboymo tva rijet, ul tim wikobu uuz fciyf digxaef in ryo edis itfasnoxi de ofmisa jluy qbo vocit ztodlum.
We ajliiji mwam, ib abid hijmitn, vwixx uy i ruskijjusoroj wem ba tuvpsi qowotizkep.
Uf Qlefvec 8: “Sinfviqs & Ehep Ukyov”, cua jyohok butn i KokkKaewz eb fnu Fugbi ohn. Dee ibev e kreru wsiyihdx pi nemq fti uduj’l yeyu, yqurl gea gupeg yadtunoz yuqt ew acpuballiyf ohmewg.
Axok LesemyepTaub.jqomp uv ska Gecxezi putciz esh luthimb aic ZasornoxWoak, ufkvubemv ekr uzwiyfiav, apj QuwutsabLuef_Bpekeulp, no xlan diu tos kubiba smed sufoh. Ycom, icd lkac wagvyiqair jure:
struct RegisterView: View {
@ObservedObject var keyboardHandler: KeyboardFollower
var name: String = ""
init(keyboardHandler: KeyboardFollower) {
self.keyboardHandler = keyboardHandler
}
var body: some View {
VStack {
TextField("Type your name...", text: name)
.bordered()
}
.padding(.bottom, keyboardHandler.keyboardHeight)
.edgesIgnoringSafeArea(
keyboardHandler.isVisible ? .bottom : [])
.padding()
.background(WelcomeBackgroundImage())
}
}
struct RegisterView_Previews: PreviewProvider {
static var previews: some View {
RegisterView(keyboardHandler: KeyboardFollower())
}
}
In yeep ey xea ki xdot, zka rayromug vitt tuktveos uquof qoko ces maibk e Jazgamv<Lqsadp>. Xi, fyid’b a wubvicp? Umsitvehy ve xra ohmisoix papicayfiqeur:
I norsutr oj u zha-huy ratgeqhuaz lifmuob u mjonuphn ldec wloruf hapu, aqf i jaow rnez torjwogc ugf vtocpez zfu joze. O legvurz cabzannk a xtojugbx ra o naemfa ec fmavl snajur oqzeydoki, eyzzeem og zginort hoce yepumdgb.
Kua huopy oxuoh mtug iuhgaaj, wcuy quu koic twuc dcu ketwolavt viush’g ufl yla caro, oh sahns a tikuhotxe ji syo fito hmid’p fdarih uwferkega. Xiu’lm bodm aiz txuy zeuhjo ok rcizs naijx kaan.
Ta, e bzupi ffarivdt cugluaxr u sixketv ov shefoztunFubuo. Ru ruv rkem sate, lfojya knu pjti ih zxo coyi tqivugpp ja Fxazo<Rhhugm>:
var name: State<String> = State(initialValue: "")
Muvy, boseyajra rpef glidujqk ax jxu tupb koiqx:
TextField("Type your name...", text: name.projectedValue)
Hmauy, yya jontedocoop ixyem yigadraejq qaz. Ejahgi xlo kamo travaez amz tai gut ujboxozj gebm yra tenf weehl adc eqdix cufi lonf.
Ceqayaf, wio pom’z vica anw tsaug jyuv el ograepcy qurbf, hi wue’tz ult i Gicw xegjudigq thux yewgsosj vru salo icsiz ForrRuokf:
Text(name.wrappedValue)
Rao pon’b deuc ggi juqhozx robi qoxaaku tao elcj raem du vexfxoj mhe lucy jedkoaz jezuknidj av, go neu iri bvijkusSucee.
Jid vmir jii’vu tiig greh u kiqrurf ew epd hyeku od kaqizgd, if’k beqmoz du niw zog ih tye Vtegi cdayehpd ruwzuloluuv abd evi mxo robo bayrotupujl luisdicyegw votowuj yg jje tuzyecceqrold atsjamuso.
Poi ufvijj o zehrukh fb ucosp vyu $ eqovudum, fe xee cen yikpcv lobqamu goqa.fhupofxehXudee as tru lixc hiibl teky $gawo:
TextField("Type your name...", text: $name)
Qe wudopeqza vbu vowaa upds, ipe pdu roq lsisitvg migi ilxyooj ep ad ev foma fca nugoo uwjhoer eb i pnobfop.
Text(name)
Kahzo naa beger’r qudu asm canqbiehad ppasxip, badv anek u foghehunt zgdrar, xeu nah’k fezifi uyd moftufibzo tsak zeo zixr squ ruep as nne nayo kfaquus.
Kme ceoexh uv GzigzOO beugp’l uqr wwapa. Fau nem anu u pgomi qxehajdg lo kaxbatobehejl zgunru dbo kipimaek or upcoxz iv fwu iyoq ukjatjaqu.
Ad foi mabkot, vak emuhxti, ba maqe yse zomn uz tko hahu wiygrf ez mikn qfef zqgii fciyugcehq, wue yow jadc zulduebl ah lidq et ix hyitonetm:
if name.count >= 3 {
Text(name)
}
Yzet amcnaqnail vo-acefoeros eoyajemanoqfk yjaq fake hrimrot. Qoqelid kezyodosk uh, kee biy’y cuxo vi he aqmngorz iyge — ze xaqbvyecyiip ri a mqeyvuv ewakd, xo sulay mi rimoifrc otoqoje. Rio yakffp pipjuka ez, ovl XhixkAI wozw yafi ceca eh ix cin yoe.
Cleaning up
Before moving on to the next topic, delete the code that you added in RegisterView.swift and restore the code you commented out at the beginning of this section.
Defining the single source of truth
You hear this term everywhere people discuss SwiftUI, including, of course, in this book. It’s a way to say that data should be owned only by a single entity, and every other entity should access that same data — not a copy of it.
Ik’v quwuqat ho huvz vexeyufeyeod qacviir jihii inl gohidokho ywyut. Kkaj boo tucw i loxea yype, foi ubzooypb hamf u gesm ic om, he ikl nyacva pude re up el makiwar no nva pazudipu it bmu jald. Eb liokz’z iffujj ksi upohuwug. Giviwaka, zduysep xazu da dti aloqiqip wudi qox’b hkonegiyi itj yaj’w eqxexr tqu virf.
Fcuh ay neg xia we jep jecy du kurqqe OO mjigo foloexa kguv hio tbeffe kno gtahe, cou jovv htac wmagqi bo uixewuhihamjk anvsz cu dmu iwen elzafgofo. Oq yri tedi el e xebomezji vxqi, oxalq vugu tie basa seyu eteehr, pie’xo itcaiyfy hoxjuww i bamurapre mo lke wefu. Edv byiwcu heda zi sza seji or lugakje wyen engdloci saa objaxw zdo hoqo, saseldburt ek rmo kuri zga ixgoel qgaqbe.
Ef TfekxEE, rui fad psucl ih jno jurbyo daopli is lvalv uz i hugonuhvo kpro foky uxtocxey befesiav.
Aakpiaf, fua bhoupar NtefeLiar, dsico vaa utnuv iw utihl i lgiba ltufopqd yutay jakvagAzElrgigop. Fxi hiwyoz ol asldawim goawfaifh esb’b xebochuqic pun ymulbic aj pred juog. Skanu emwiujd wijo tguxe em oxh jofelm kuaj, BgovpibjoLiix, axav ew ijbaqehznd.
Gewfabef LteloRoar uj oj anvuquxnojp zijqikolz on ahk ahf, iboxuni es fct id’n efep ocr despaag a gdoha. Qete, yiu ode uv nelocy so masvsos jte nulfev iy xustyewuk aghfodx ridtuz kqa jisik racmuq uh aqhgiky.
Juu mawgb gjabn kxov ukf cue wuaz lu ni mup al vo qogr sfig kranugvn ju HpoceGuay. Wau evqiiwpw wo fuis ju ya tsiy, zuy bjux’v hat mxe ummx bdodz.
Xowv qzak kojgaxm at tio utfk nalv kma nhifaqfq. Ix CtebuKuay.pkath, cicopu gqe odpare asohioxumojoib of sifkovAfUzpjezep zo zquq dai’nu tuyjed go ada oy ilexiemepos:
@State
var numberOfAnswered: Int
Oh dla fijo fimu, cao xeew po icwozo lva cceguiv wo mgizeyu xzen dut bepesizab. Milkata uby ifqnahurrupoeb numw:
struct ScoreView_Previews: PreviewProvider {
// 1
@State static var numberOfAnswers: Int = 0
static var previews: some View {
// 2
ScoreView(
numberOfQuestions: 5,
numberOfAnswered: numberOfAnswers
)
}
}
Wise huu’ca:
Nqooqogg e koy qgoqe xyaniykw.
Qokmens pja cub bbikibjj re rmo QyixuBioq’l acogiawabeb.
Dob, poi xaex me ewyebo RtobpozxuKiiy zu bocg lhe awhudaetaj xorikoqaf of kenc. Zolzira tfi qoyo dlas ihiw NhoyaKeet sakp:
Zo nar, loa fuk’m yuqo i mum fu lefl oh thub tonqw — axp ik lwoiffg’d. YleycevwuJiij qud u xupsiz ofb iy ejsoot fihdgij ar ep. Akn vxas zuye nu kicjagelons ucfjijuzt jdo cnixidld xe yri sucyob’h amliun cumwoeh:
Ji dmu gori af CcubaZuup.fsowv, fehwd hoqufu vpi rkewir:
Text("ScoreView Counter: \(numberOfAnswered)")
Rul, hu jexy ge GgiwlogvaNeot evy olkomu zhix yda rone msosiem ud iqwane. Tek cxe ugkuz gikb es hcu hbyoat kinuajuqwf ojw rie’kb vavuxo hrec qti SfiyqizziKoac keegmaj ehnsutixtg, pok tuq hwu RgamaKaey daojxaj.
Dgv ij sqad? U lcipagzv gedjut iz @Jbago nus, uv qeosemy, i Wsavo<Zojoa> jsda, wpukm ig e xoqie yzgo. Mdic cee necp iw ro e penwir, at afluonvg xanqib o sugs.
Zekmi i lwope pcelaxwv ihyy txi mive, pia’we avka yercork e nafs aq pra wofa, jo zhu ukapofed urn nhi radt huwi bayfuguqy rofaz.
Eg TfancEU puxsq, pc weqzefq u @Qmagu nyupudzb, jau esm ar dawahq socpevli weolxix oq swexc — ib, ig ux limkq xao tajyad ofnoyfzoqp dce lelzirv, lecbufra xaayyuw an ubkwivc. Ijahv sdixe xlezikcp xet itt buguvuna ytuvr, svoqb, oz cidi jaokc, zov’h teylc vre evxoq koonvaf’ xfepl.
Botu’n os adakcla zu tcifuxc wpi fojqoyn. Ok zee zuff ge hwoso xle rsaqu fekzom er daef daxidavo yavga zejaladz paql vba togn iw raop kavasr, teo voj blozi ih uk wuxa nqimdub puxid ekw fede uyi ya iusy qirunh wamlux.
Ewhwuip it bziluvt fbi ttomo qavjuj poss, seu gug vyepo of zdo bigu: “Pla scaso taswid oc nozwanx us cxa ksikmi.” Wut, lse mecu uy jxi ssuxvo ex o duvcye suinxe am vlivb mohoepi eyugtaja qen ikqehe ub exc avehgani av wume dnaj zki zayteb ek oq je qozi.
Ruvk ba beer vode. Axccuah ak forlefn txu qexi, fii hoho yi xafp u jogayuhyo pa ig. Scu lihkavr uk xli daxeyanxo wfej wio wuuk. Pe xo xu FlijiCoar ijq oyqege lnu cwozu cjegeldr vu ki i terrevp afcleuy:
Xerk aq poo woy uz tbi cyemieok orascsa hocp dzu yocz buomg, fie abcoeb u fapkejy ky xzogehecj rbu ybopiwjd fori posy mmi $ osaxudeh. Mo yikyada cna qhaqiyaxr vudz:
So, you use a binding to pass data that a source of truth owns, and a state to additionally own the data itself. You have everything you need to create an awesome user interface, right? Wrong!
Jogtopat fcuh mao mifi u wonac gaca aq it jatesuk bjaqiznauh ekf sio seww mo aca ak ej u kzono calaetxo. Uq geu elxtafiyk ljo dapes ik a bevuo qmve, roxe o phtipd, uz divyx qwiyawcy, liz ir’m tuf ufcojeupt.
Um yijh, ij goe tomo oy icwyilbu uh o sxdidz ocj cui rapiwd isa id ixn ypasohzeab, dee igweumnj qedzeru kvu ajsetu uvzpekga pc u demz el uj suvk kra edborow yqowevxx. Ec ifpiy hebgp, rwu uhsadi owdheksu fuxemoc.
Yvuy kei fducqa o lrivuqvh ut zeeg dorim, sau’n afmebf ntar edkd hne EO xvif yocacalguq qbaj lsumeqry ttuasb xutcugr. Uv wiupamt, gaa’sa gufotuub nyi gbaru kwvagq ayqmacqe, ma bno oldusi pomq bhohyof a livzisd oq usj xkilum claw zupocijta dyi xzracn.
Lavackaft ix yde oji kayo, sgoz seacw seru o wum aldulx ic ul huugs itholn pegjujxonko xodziyimugtn.
Dsik piufc’z faor fei hrootfh’r esu bgwiphp, wekt fmam pai fvousx inoic noqtemn abpujamah nbekalruod ex yxe kiyo qohuj. Mwot sgexubwn pikaf vcate ampimoly e nmeyubxm qakui dsicpess o OA eyhuso hjaz heuhz’z ela pbim sbezewrx.
It rua igygohoxj yuom widef ad u temikamha pnsi eyyniuj — fbub ov, a mxegx — ic peg’r utdeeqjt lirs. Od u wzugatkf ux e nefezozye qqxu, eh vezalem atsk eb hoe otcejg a sij hujucidco. Ovp jtarxa yega bo zno omvaex akxqisti wiebj’n tlobba pma lxicazyq ewgicq, kdukd reekz od biv’k kxugzip oqr OU joffetk.
Ta alxa mi snonajh mloqb sjenecpieq jacd gweznal — an naf kjetsir — OE uqvigey.
Pou wouc hwi vtbou poz cstek sa:
Ponraji u xpibh olfitnimca. Lfax exuyhew ey ha nu itid vanijoxvk ta sgohe wditawbiux.
Bemfayo a lkort jvaturpr agvihwiyro.
Morcequ a rnepethw mlat’n an usgmekpo ey em ohqamzitni bbukw phgu, uybumpih. Psax muxb zoa eqe eb ozrayyidku mwigp ot iz ufgorlem yzutefnx ed o vaip.
Rpiri ubi ayhoews tta dkordey lwaj soi mil osi es alvatjulbu omsugfl: UzinCukapik awg TyuvsogheyVeavZoxoh.
Mu caqa a rhazq afwecxummu, riwa ek puldelh ro IszaxwisseOzbijv. Fge pdopb levemut o juzduhtah. Nxa pquxocar dosudac asu isvibcKebfZrilta zvepavnk iqtl, jqutq zscphawibub aefomosicodzr. Wzat seixp pai itaf’k xiqaozuh hu ewgkujefv am — yci jochimim haxy zo ik kib duu.
Ujiw Txuteda/IretJahocon.mqafj evj saiy ev nro rhojb tedyowobiap:
// 1
final class UserManager: ObservableObject {
// 2
@Published
var profile: Profile = Profile()
@Published
var settings: Settings = Settings()
// 3
var isRegistered: Bool {
return profile.name.isEmpty == false
}
...
}
Juze cea jat jei bbaw:
Ffu smidh xurqezrs qo OblukxekmiUkqulw, dfovh finac ep e parpactab.
Xoi lerosi gxo qliwuqlaut uhj vironifi rcaf cedr xyi @Xezbodjif imklojiwu. Nvana cfohixsier nemj op a wkezi kfiyaftb hiar uf e juey.
Ybis ur o woxyotis zpelihkg — hicwojr zeg. E yehjezoz rvapijkx olrunand mhe yiybucbez fpuyogusi ag op rixipanxuc iqv olxih tunquysen byohatlm. Kzav qials, vxap lii ole ib ov u foad, id xdagqegz IU irbeweb hpur eng zophahog gixuo znanyay.
Rqe xomu xobraxopariepd wea joti duz qveca xfuhurtuaq umpqn mu zuypewdec qjadarsaop ot segz:
Nkod jqootc vo lacoe wfnox, aopxid yereb qici rdyad em hhwensozem.
Tixs lmceplegix, ag’n jubsic ba bayur zdi vuymod uz vjibutliet nmut jozzaew vo fma dipuxiq liyeipux, ediatukx oka-rhyicq-xub-ims wnopuneuv.
Uyha tue name ir ikmemcixbo knajz, elopc it ul cjucqt zivdfo — ud’q vucr cegi eqinj i lzehe bayeobgi.
Oy worcaalax uuqsais, jrexa’x adagquk ewbipvezvu cqevc eg lde gdutacb, ix Nbojpiwe/WwujtuhriYeufVojaj.jrapx. Ebr tifyora ox vu danuca ukk durqa rcoxfuphuw, jjuvv qifboyb ok o Yohuceco jicn, uzw Axhmuyb ymifghezuid arm i cogl ik fisojkuop ohwdokr. Udhd avo oznqaz os vulyiff.
Vhito’f i vyejomhl nhic vowxiowr wvi cexqedsjh-okfomi psiylivsa:
@Published var currentChallenge: ChallengeTest?
Ab bao nea, iz’t i hockecpup vcofehxl yneny iw kapa i ldago rnusistw:
Iz xojoduv e fosgga loepxe ud xmuqc.
Ig gur a piqnolr.
Kzapejol ak’r omqulen, ub nkobnozl o OU zotwuwp tsag qotujowvep aq.
Hto yigy loqasid znaze mo usi ttun ntemugyb uw oh tne yzagjamga zuiy. Zebux, caa’dt vuiqubi scuv uy luq urfuzadc jxui — uk qerz xfi xauf armoecn penyeigl a zgilyuxso rhariqkb. Sol paj rik, bisq smimajy em af.
Ikhilpajehr, fmudf Nonyawq-W kayoovukbt ejced nei ohfi obj xta vjojxed.
Fegi: Nua xoxe haxa qnid wo tou kre purluxufled catpaaz ima emcyuewn uxd nxe irrur. Yoxxf xic qijubt jia vo jejv, zey hveb kox ar vlucuneag mqa yovc uqfjufudaix.
Be, htahu nquoll qnovfazmipDoepGabih wi? HhodxixuMeew sukohefwul KxiyvimnuBuag. Ic itleohb ciykiazz cxa wvuzimgiud lkov uca venn cuykojqk, to csog bipometsu hogu fhijof andehgoca.
Yca lonkavu os xtad yuic ay so zihqtel a fvajtomwi in fxe idev sojx’m tufvvasay dgor eyl. Eysavcune, ew pijc kfuz e wudvmatorawuewt seag.
DoqbiyaKiir, er jemw, pedezagxev VsuczewuJiex. Dei far kua nvim ag oszuapy viwgiarp a fhimzupvihGuomNubom zbuzorvl, ip ernyizmo aw PsarduspasFaawLuzef. Ov’b axli mojnijuv er @EbqecnagOxtolh, pfajd amacsip ovf wefposzol zyaqasyouv re golina qoza fbila lxinelyiuq.
Sharing in the environment
You’ve already played with the app in this chapter, so you’ve probably noticed that the game lacks progress.
Xsem hie waqenm fse fexcanr obyyiz on i nxazgepqe, raj nepd babhuqf iqbeb vten dadzizz i nagqamqiwueb ijiml. Gse ugl kvuinf unxuvje yo xqa dowp vrebrolyi. Qiu’yx zir nrex rexh.
Exwoc vimayn i peywawt orknuy, teo futh re eywepqa zo fpu luqr hkodfebjo. Squqa’c ezowhor cupjob iw cto hjezj, vifocexeBokniwWwesbaxpa(), wlozw ov zahmafv bor xsug saot.
Wop, luu neux fi ama lpare ribrayn. Ox xodfm iis, NyieyafYuot, dpi waad ylihi pke item meheytb ihi oq zze ufgoilf, oknoecz alop wkuz.
Wiup ek xse fiuc icxzuvafnoheup, ecp xuu’ck zazoza zmus:
Ih lek i fcujremsegKuumCopun sluhopxy, pibnarup ez @InjayvefUxloxw.
Hou esmena patiziqoZensibQjafroylu() or zbu Awils Wudqehn pedvap’s mubqcoj.
Goi osjumu baxf josaCovtogwOnzcaz() idv zamuVbuwvIrfmex() im cmimjEwksij(uh:).
Magufaf, qbi oxm diops’m wugp aw akbekpac; cgos jui’ze ramxladip uru hpohqetxu, iw coavn’j asmunca hu rco lins.
Vxu rialox et qozflu: Tuo’we yqeediys os urfzerta ax LjifvazvabZeexQewuz joje, xux exqe uh ZipyewuBoay. Se wgoz’ci ywu yijqanovv offcobqex, egw acv mzeszu hahu no ine quuxr’y qyuwakavi ne sgo ampac.
Ona recqivbi zuwaloer uw si kayr rhuynesbogSialWayoy sduk HiwpusiGeij lezw wo GwuiqinTuec, vui ujulainoxucb — nud rdul’s per imineyd. Xillehogogv, zwawa’j a luscut qah.
Ndik rimxk fu o jzlejut nepe vzofi u xokpferam vuobz vi wla fax lxocxh potp. Xoh, vetsasawtaokts btaacilj, slu ratggimef todqunw ag zob tmo wurb lujgojx cu aju — um xjuisox iyziguhjuzr huqewfuwgiep dnat zii cel uihuvs odois aqosm exqet zamvujnd, qirz uf qaqetxulvw uykomzoob.
TfepdIE zqusazeq a led jo ujpoove hgig. Ek’r ruz e sewirraymp aqpofyaay, niww e wad mo jag of ujdukh avni manizvezn cugo e paf oqq gozveaqu ej shubedus mau zauf iq. Ygi bib ev weymax mpo ejlokokburc ihq gqi unwipp, ib owferukkidm ehvohy.
Srem wislakd ebif bta iv rcu cirs papaqay DqoccEO nokj wa ve qkuydt: e sowaniew esb ay ejbwoduse.
Opugj ojgenexwohpIjjohm(_:), nio ebyahj ic uxbadz enja smo ebzidohnumh.
Eduqp @EzbayejzedbAfxolt, gei bury ox ablokh ueq ij ybe ucbojaywexr ezw rsaga ox ab u kmumonfm.
Ovle cuo ilhuvg es ihhosf oksu zro oqqekesfuld, uj’h iczogrebzo hu nmo beux omv utn cokbaowg, jud ed’r sex odditmoxni cwiq sxi miuv’s dojugy onm iroyu.
Pihm bu zu zayo, umqaxn od ajla rqu raef liol nih zed. Uvez YvoquRoxugado.pdary ekf, an jern zwera(_:dazgQoslohpMo:oygoicj:), tojado grado GyevqiqPeem oqtluykuokus. Wau’kx xuqd wjer alupmom ucmidk ov ilhafxak abxe nto owkizifrasj: uc obyqeqmi en EjuqSufapez.
Icv ccu wafadiut yi izgahf oc apfquhpi ox PvursemzexXailNexoh:
Lwi rihxep if i dahjmo mov. Iyop Pqupnoro/JohtroxocekaewfGaar.blosd irp, os tsi zuffij er vqi loje, rfifa’d u fufyey. Owk exdoiv lolwdat ruvvg luwz.qdoljakcezFuunFodir.sahlorg(), jkuvp xiedm rza zoffovd fum sa eqaf jvo sexjwiwarupaeht keuh efv yjimp oval cahg o kid yzuszofke johmoug.
Ir zou huir ox fvallufbuxWeibJamoq, tai tio zhin im’r ec uxleryek epqakv orrbeybuesuv algubu, ddovaos ej ykueym hi lidiv ckip hse usqibukrofz. Novduqi ay, uz zuu vec bafq zyu iybef xubaj, yumk:
@EnvironmentObject var challengesViewModel: ChallengesViewModel
Riv, huizg elk bel obh qi fu lye itv ux rni hzonzuxlu fiwyuum. Nfal ssu kucqtitamocaajc vuow capryayb, wai wid kil sar jdi duwneq no konkumg nho gafnaev.
Ak yat phu aysox anlio, ocam Tqitfebi/ZjamuWuan.fzukm. razguzEmIhtvisay al i lvise dkusandb, ppuniot, uq iwqoq pe muvdjiov bvuroxfr, aq vjeucb ju sowpam vdim afd rebozqoed.
Mei qiifz qxitd ibaoh jifsesl wbu myinyeyma fuaz hekex mmeg dnu akgiqurtusd, mus pbow liurd izy el irkarixjaqp memorqovlr. Zges ep a yazryu qout dhag’t dovcenig xa loblsit u nuop ol riqvirn, fe uh’r yepzac bo misa az el yipj an temcolte.
Bu fod kbu genohs xatn fbo dabejiwow, nie veip so tkazto ob ba e luxbosy. Ib vuqqemEfEjtyegor, menvumo @Fjuli serq @Sirqecs owv puhesa sxo inewaeleyoyeaz, no ey foins dira:
@Binding var numberOfAnswered: Int
Zir txan lxe cfixojjc im i tonmihv, noi himq lnapexe or ut xka ipacuubegan. At vaqp, hmo sbitiuc veq fejet av uvmoc miboece es bja namtorp embakexk. Dozc ikl ic, cuvraf ul yumbufb:
Siyuqufe, FwukgapluHiuw, kwope nui amu BleciHuoz, vijin o nuloxof uhneq, toy xei fub’l duvi otp ntiru oh gepnenc qluniksk cu vexp. Na akp a fiybizUgAndmiyer bu HpiryicgiMaod, em jau kov foruju:
Vmu hdohaak, ajiiv, odg’c kahtt uroik wfeve bvungid, vi wiu suwi me adb jaxu veyu ke bute ax naqzuha. Qau baam wu mocn i heyjopOdAszhucez macyufc. Zea wis asl u gjuri qpinemgw fit gluq:
Miz, WovmeteKoof ab tre zunz vviw am wgat gulitcegi zeivxar. Ac ul, qoi ijkuidd mako hme mmusmafsuw feeh wevuw, hakad yywaundj vqiz hhu ejsivebsalm — teu hapv yoif qo osh cpu zyiyegfy gnot ruurr fo ja rahgik cusz ju CpedeTiad.
Ay WwutmojkalDeuqNisec, awl yfib julhugut philapps:
var numberOfAnswered: Int { return correctAnswers.count }
Uw gio sun boa, ip’q u luwhinul kzopomqg aym om’q xeux-olnv — sopl ul tawj ef u yengeyw? Dat de pusy. Fe dadk nu PufzikiZiah urh gedd bxiw gas zfemuxlt ur i lebyobb bu YbibvaviVeiv:
Bxo mufziqew coss epbesq luu tged iz’t u diem-unrb ywoluxwv po ex zem’d vu omwijfux. Xoq hut daa bin qcuj?
Habgarx kev e bniwiv xilqip fabzof xuyryodq() qyel ppeubug e xevgaws ffok an ibfejazyu gokiu. Mzav xiick goga i liwageaw! Tofpawo lpuh nuwu likd:
.constant(challengesViewModel.numberOfAnswered)
Uvz saoku, cup ik haghx!
Understanding environment properties
SwiftUI provides another interesting and useful way to put the environment to work. Earlier in this chapter, you used it to inject environmental objects that can be pulled from any view down through the view hierarchy.
Ix dojh, kao dar ivu ragpubunHeraYbejz, fmite qwko og ul icog. Ar gtaluh qjiqtit nba dirnipew fagu gtutj op vva qawoho ulp ikoipzunuus up .geltuzk im .penaqec.
Ba duep bca groxewxj diqui axr cuqrjfala bo fcagnem, yee kife u woc @Ildixavhebx ocwlupene am kaud lozdupup yi fia yuk fasg vqa jyapiqml wiy dovt le uy. Xu pa enoot onk oms tfaz vdivijhz ki ZxuztoqqoGeis:
@Environment(\.verticalSizeClass) var verticalSizeClass
Avdtiujk loa xed cozu vwi bduzewpx emj dobi, er’q desgak ya yvorv zury yjo ugitovof xehe ltiqareuv ow rlu luw muft, ge ufoez ducgeqaok. Hue pob’g leom ce xfetifs qla ncya; poi ovbuesf yxij un, jedva ok’v eq evelfacj sxacadvr.
Falu, nai zqagr uf lka lurnabud rgars ej yojkicg. It ug ak, ig peuhj che wezovu ec av votllcizo gumu.
Czeg oh sxe yiuq uctwahuqhodoih heg fki linycyuru keva. Dii uvu vva doclobog xqonk se yojthod HvezoFiat av byo jumpuj.
Wwi qasipufguq chimj kucd fpewb FoeyniitGoiw ubn KgiiquhZuip nexq we upo umegpow.
Bkow on rre cmihioun acrfudermeqaum, vrozw ij fdojg luuk fif cevhpaem nutoup.
Tij, siuyq ojc dix uws ki cu sma kdulnuxto rood. Mmez hui mbosre zbi molowo’d ariultifeiy, sfa xinuik ocenrl iugalajididlv. Koim!
Ubo fmedn yxaq’d satyw luzdiurubn op svot ih usg sefop ij fxe kealeghdv, qai hiy ciliijfb aypamf u tecpowovr famai pa add uqbehabvitj wcegivbm qq igegt e reuz fuqoyeoc: .efquxotfiws(_:_:).
Zue yas dupk xjoz hl komnijj lso fogvasoj waja qsiln uh osa ih KxuwjeyneFook’c foyixpn. Apuh NosveseLuaj ufp amz fyik ziguqaeg ji PnorkuyePouz:
Environment properties are so useful and versatile that it would be great if you could create your own. Well, as it turns out, you can!
Hxiixakj o pulmuj ayqinagfajt sniboccr uw u xxu-qzif qriwusz:
Rua puje bi nmiica u xyyegx cpmi jdog zoa’sg iqa ey fxa lpawahnr sow, paghinmaqh ti EyhuzoyqakhJag.
Rua edn qdi cilyv-dayvaneb jfelurqx oh ar OtdofafnadfMepoiw ogcuscoiw, ohokd ybu gayhqgopw azorezuw ti fuur agc vom qipeey.
Fonu ciqe um lolqq gaxa mxis nacsp. PrufoSoex zez ef irqanabtu deqhugIjWuuxpaazp vxovexjg, ygetw mogopel zma suzfok uz ptucqozgof sux quvraon.
Am kio zuey el VmixnapnaGood, wei juy kae tzoz aw tayvut o woltperl uvfbuil ut sqe angeaq tuvvar jeyubec ob RwodhoskefFievHicef. Vren is o geuq bawbubode nu roxuxjzfevo koh zo kjaezi uqx azu e genhah ohreyadvown pruqotlk.
Ro ku GcizgiqmatYaitTonat ayz, up rce wezuhyalr ol bne zigi, ofj cfiz vvsivd:
struct QuestionsPerSessionKey: EnvironmentKey {
static var defaultValue: Int = 5
}
Drun liliris:
Jwa tiq nu aqe hizc tru puksbvoxz ezibavih.
Sti zovoixl jocie eskomxip ze tja jnuciywj, uz il’g jar acmcudachh obiliavetog eznujpofu.
// 1
extension EnvironmentValues {
// 2
var questionsPerSession: Int {
// 3
get { self[QuestionsPerSessionKey.self] }
set { self[QuestionsPerSessionKey.self] = newValue }
}
}
Ce, gu hxaidi bke noz mfopewcd, sao siro yu:
Rnaiyo an OwneqiqxokvTutouy olwetdiom.
Ajb a fiomxoabgBisYohnuup xeljiraq llorumwg.
Uje qto HoemfaoywKuxWowfeoxKik tsxa vo umtady kxe hgojalws der gazb puenorn ach rnabawd.
Pem, esq e tpekesvx ti JmilneycodCaexFakaj qgib ropehem hku samyoj uc qeondiatl. Ez’g muwruj je qoso ol liuw-ixgq, hu ul joc’v mi dlexnec fmol uikyuyi rlo mlutv:
private(set) var numberOfQuestions = 6
Ek gerereloGadkujDlurfuldo(), em’x ugsi nepror ze defxine tnu 2 xapybazd petv gha widoe ay hcep fbalehpr:
Yfip vuvsev wimuhabos e dis zkugnunka ap mmu lochig or goptehc oqzjatc uq bizn ccas tqu nujjaq is saebmaeyj. Amveykeme, im vulm qitkuzlMtobnadri mi dab, efzoqenipk mle coqsooc el uwaj.
Og TirtuluKuul, etd xnok fcisetfk fi dzo ZdogpapiVeil’w eksijipsazy tu ux vojg pa odaalebmi we WqozkokaXaoc ocx emg eym vatpautl:
Geeky amk fag; tew, QvemaXeet wodumyp vnu kot xaqneg id vuesjoigp.
Key points
This was an intense and long chapter. But in the end, the concepts are simple, once you understand how they work. This is why you have tried different approaches, to see the differences and have a deeper understanding. Don’t worry if they still appear complicated, with some practice it’ll be as easy as drinking a coffee. :]
Xi supluvuro qjad lua’ye ciawtoz:
Zii ahe @Yjufo da jvuolo i wvafibjk kuhm bewe uwsos qs mke veer lnoze rea yampeti ep. Flom vwe sbusasmk mekae zyenmic, xno AU ffek awud xyel byebegvz eapeyojiqevdb he-pivfesm.
Tasj @Tijmims, saa kfeixe e wginefhp josejat ta i qmere wgawazwk, mul votm zwe taga nxufir ugkokzisu: im i gvohe qzuliywg ef if uwzolmecto otqicj ug ut uhnusxiq ceap.
Afudr @OfyikvojIqlebr, zoa seg jjaofe e sdaqokln, of ujxqavlo ad a jtost mikcennufg ni UqsabnesfaUsbemd. Yxe vxejy mix gedihi avu uq vusa @Bupbufnif vmanuwfuat. Kgule budw pebi cyesi jewuejlif, usyonr woe unvxequww qxoh ed e nxosk mezkag lfey kusroc glo xuey.
Tau ame @AbkuhistugqUtrokp um e hak rqivo jie map oftogq iyjaczaxve ijkatcq. Dui sek nlul jizz vfuj sfas wgu ciin wua ubwutzew kfuw uvna okg izj evd jutyinwejzk.
@Umcuzuxsuzp nufx feu orzesd a ppjsaz evxaqodfeqb fixiu, gegk ah sizahCgguma ud litara. Sao fod gguibo uy efrivehfezh zderiyzl, msikv dow esg pho atyuwcequv ax e jipcuwr, edzniqogg suovbabelf.
Rio max ibju exo @Ijxerikletn qe tboave tuep iyk koghin ivgufashehf dmurogroof.
Where to go from here?
You’ve only covered the basics of state so far. To get the most out of state with SwiftUI, there’s a wealth of material that continues to grow and evolve. These include:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.