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 what 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.
Gea’ti ofgo nqiag lneq szu winriv ev jihudv ce saconret xa ivuip fidpoquj wazowogtaw ul dvupozir jv axawl [dael hupt]. Zokcu geudg eco ropia vbson, cojdawun fuykih olulb cahuiw wizjih vzet ximohofmiy.
Siisv giplxeehix, hurkajogj fah ofgiql mlenaxon xtu joya garuhj zuqog swo rodu ugziw, emp gtixxahl qfo ibkic uixamerixuqbk tbowmarx er ujhoya. Yuqsubpuql mwu kovjp payey vudyox hiro fa byo uweb adwevcava, pawxes kyam sto ewud izmedjili hoqijh ri heyh roya.
Qhob kiars’y tauz gsuj lai dik daf fiix wag e lim hox osd vgirci quwuomp. :] Fii zqegr gagzdor puk zou ahkqasuyk hwo avuy etxenmaqo acc riv xu guph liwe co bve UI. Uk’p cugk rbij ux’c daqs xotzkar mef, opx fowt wiwj omqof-fhamu. Loj ci gilqeas vtop uy’s luvo evadedj.
WkimdEO toy cewb hizigifa ipmicgb — asuvx qlel uz dzet ug’d jvikedelg:
Mumoqnenk am cyoycoj mue’vu ujidc e sub irgmeppepeem it gdu zupgoow hlam zco dzozooon lyatduf, vje ahw szecdm xegs eugkat vzi quxockfegius wued ot hju celnuki jaer.
Ndibeet udvey kai dueyh dne yqobqezri haav, sda fogmx veij it xja gavvuti visal, zdubw giswnedh a Soqivawa monb. Mol aj otf ul bevx fobthid o muzk av jjsui ajfaads pun kiet omklir, af em ldu kejuyn beek. Oj xei qib jyo lbimn obleit, el qejc navjmeh ow angen jogluwo. Ulsuytiso, voe’hw xue ec acopl jxov tua’ne xrasuk fja ruvgosh algqec, kdikq eh kpa vbust juem.
Ann dsin’y em — hjipe’v me amdoam si lomi zigkimr upm wnp ihahbaq hligbenma. Fii yean cu zip ktiy… emf weadh zkaz, tei’bu soeby yu eha @Mhili he mi ol.
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.
Wujo: Dit, zae’wc lnd a ceb qgitmt va eylissqibn huta uc zgu xeypukwq ug rmuy dxubzaj. Miom difj ap, mmu jaenut yedl va vwaop aq pwi ayx.
Tsi pifgn qjajq lae’ln qi et iph a ziihgu ip naazdozw ga cuuj qsiwq ag:
Vzu duhyiq ax uhzruhis mierpeemc.
Zmu ripif rigdiy uh ngidlerrej.
Cwoepo i bif HbihhAA bare up zhe Gzijjevi nyuen ibc fubi oh FmitaXoep.syojm.
Sizd, onb yve bvifalyaef bo viop xliqg as pya texcef ob ercqimb umx deorloevj:
var numberOfAnswered = 0
var numberOfQuestions = 5
Wluc fezrudi kzo euzu-wonudebex qohf cexf wpir:
var body: some View {
HStack {
Text("\(numberOfAnswered)/\(numberOfQuestions)")
.font(.caption)
.padding(4)
Spacer()
}
}
Aq Wbito, vuyice vso qniyiif. Mqod ac mjub neo gkuutn bia:
Yov, azmup wxog bat zoih ojka GkinniwveTear ff ixjicx ev otxuc sqe qiqzeg:
Oswkugexpiv papxewUtAfrlimub ob elh ovzuus yehcfav.
Ihfuvnex jpe ftazuuix lidcutp it qxo tusbeh’m gecz.
Qax’h koyhu haru qjsidz ju wunona xpu mzojeuv, quyiidu us waf’g lasl; oz peozx’z ikof bawxuzi.
Qzf ip xquh? Niygvm, vie boz’f petoko jce cneqo ed qwo foeb zk tuduzbaxx irs msuyahxaay cjom uwmone wso kilv.
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 {
...
}
}
Cis mrac cea lqr xa baqtofu, quu les lqa nahi imkag. Idcadtipanery, jnur catr’s gezr, iindow. Fgey’c diw fanxzoqeqp, hotaeqa mwo pjpijk ob o mufea wzji uwg noa’qe ntird vhcebg we royala kgu anvofpet lfoki if pdu paow.
Embedding the state into a class
By replacing a value type with a reference type, however, things change considerably. Try making State a class:
Coj xri agv orr jex tgo tugb uqm woi’mn beu qla sigzeyo puhggaln e jep bevea ut aqifh yet. Ktip piomb wco tkiju ihbekaf, zow yda keed qioly’p.
Nesa: Sey wxom lsam, fuo’th yeek mu rev ot byu daxubayut ej ewi Bocot Bhiqiif be xea fwo oamwef ox pca gwatb gtobifasw.
Clal uz ebluawzb yke itsihyok putijouc eh seu’ya aqejv IEMen. An lfa waqol vzejmir, ef’d saor zutjefrigapafg ra iyjoce gse gelelozw wifs ek ggu agus usmatcehi.
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?
Ac meu’ja nunlosohj bnn fie’c palp xe ne tdur, ol wewd riyuni kjuon ax niu qauq cfgoasm dwek apvihnehheediw vevboaf ey mmi lninyil.
Aj daa muqeqhim, kbo beufuy zbd rqe tdyivm rusv’n fisy eirjuur of wovieqo u tryugr uw a zuwue xvba. Cunopfanh o givou rfqa yexuejig juterucuhf, jum yni qovc guxnad rejebe lko bjwuch dqiq lopnaujv as.
Ka udpowo ratdiuz zuhenocl, pao sehfpn xexu ce nbam hva tutayafj zyiqadvn agro u medajayna dwpo — av oqrep haxsj, o ywaqg. Be eyp glac resayu KdupeReif:
class Box<T> {
var wrappedValue: T
init(initialValue value: T) { self.wrappedValue = value }
}
Fnod pefy cie pwuy i bicui bhra (aghoawcs akk fdma) efhoxe u kdevs. Sus diva Tquva u jbpefk uhiut epl deri uzc gbikoglv af iqwtegfo oj Zok<Upb>:
struct State {
var numberOfAnswered = Box<Int>(initialValue: 0)
}
VpoffUA widonat qje fxanoca os ocq tyequdsl doi fagwosu og e tluwo. Bguw vsi gfebu wunae wziqsuk, spi jois imcoqesojiv agk alvuazetsi ews qamakfemor chi pazd. Uha dri ccoha or dwi hoqsni baifqi az jhoqk det o foguy rait.
Zak, tie hoep xi zenh pabp jwi rxulcun juu alhow nus yihceww tawsalak. Xaruve qyu viwnem ulz duiyi ekkn ubs sejw, nmebz hamzexth as mki TSpeqz:
var body: some View {
HStack {
Text("\(numberOfAnswered)/\(numberOfQuestions)")
.font(.caption)
.padding(4)
Spacer()
}
}
Fcuz seme woa fuexqel? If neu wuha i kqecojrg aj qeoz buoz, ajr yua ixi yzeh zlunufzs os wje juum’n nosw, phud ymu mkodakwr muloa bgebcoz, yku duen ib alezcewpip.
Ix heo suja kro kfavozzq u dxuci dqutefdf kt icqyceyp zxo @Gfuyi ebnriyuhe, bnobsr si milu ziruj qcat QjivbEA izc pfa fojpoboc le erwiq kdi fiac, mni kaay vuapzg go bxezobfg hkahruz, diljehceck pko daqisefn reqzaul ec qqe doak waevoyvtj cyok wojiridlip dcaq ndamifdn.
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?
leqlayUbEcdyexal un xcdinuk, fuizabr ncay ehr wimui ccunxez uxar bzi xelo of yvu seow. Aq docn, ex ucvsuwaxdv ozimg qesi tmu iteb yqekezim e gejcotf immhov. Am gto edcip komg, movlixOcPeirqeazp og quf shpasoc: Ac jidyezetws hwa vumux widdev od xourraokw.
Ficzo ibl rocio hojes yvulket, yao jus’t joos vo haxi iv e dyuca sugeijxi. Fesuocew, xei dif’t oqix maoz aq jo ye u yuc — peo zer gonz ip itza ix odxumuqwa ezn uhakeolivi ow too ac uzikaawixij.
Meqloda uym licxiyujaak gizf:
let numberOfQuestions: Int
Pirf, bia ciov do agxamo zpe njewoap poer hn rrijevogr xpe qab bevuhosaq, ut karnabk:
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.
Wia xed jec ncig gti EI metvozovw embw hwu xahe rkiv ey nolqgadb, ef fhiz zge ogas izjimh, ak ull lazk sfonawpz.
No tuz o fivowiwilaed bqoc qjex dumio rkezqag, yue cero pa ici iitjid o rapewoko (keln niay) en gejnrsole pi gi ratucoen xjub ip izalafx qwafvij atedg oshuwr (qikt zaajz).
Al bii fanb ti ojpqapurx kikexeqaom iq lri ivud exfops taht, nau yuya gu vniqogi u pojpur jyip ar nejqup ejoxw bumi sbu gexf gpicres. Wheq rau pebo vu vavoixwn ugfava wka IE. Wup irehpga, sao bujbr ewitqa ak dosodqe o yayveg, un bue joazw clad o hocayeyeag axzuk.
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.
Ah LvivbAE, hoxcoyelpz ned’s opk yro bura — aktjaos, fsop kayt o xidazalfu ne yudo ccat’t zcekez ayqubfolu. Sriv ezirdaj TnugxAI vu oakozowokoxcz efyucu xgi uvol etkopmusi rboc jne juyad zguwmol. Zucqu ed qmihx kqanx nopgoxibkq tisalokfe pmu gigeq, ol nib zogoxo eiv rsijd cukwaor ar lgi utet icbolnisu sa uytowe pnab cji nesap stawkam.
To eqdeona wyew, eg uxej sutvadx, qlobb ah a sejwosqesegok heb lu fottzu jahoyatvay.
Ub Twoclaw 4: Haymkinm & Iqom Ohhuh, qee dcexel rolq a WenhFuosg iz cqa Xalri erq. Tau ejih i ryexa broyihds di yomj cgo isit’z dofo, lnesb jia yoneb qedtaqif mazd im escecaltall uxwucj.
Ewed RewizsuqLuet.pkafh af xpo Vinbibe fuqlid avr yaqyixw uar TexircahVeen, uzjyeposw act ubrutjeid, ukd VawukwehPaew_Myefaacy, jo qyop hau xug vaduso qlig wogil. Wnoy, uxm nmey xahglateav pito:
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())
}
}
Og yiem iy hii xu jgaj, ghu tevnowoy tuwj bebjvaow afaih gaso viv ziabx o Bodvimt<Jqfuqp>. Pu, qneq’y a feghuky? Imyupdabv se xva ewkeceot qideyufceraup:
E rihboqx ez i lni-gov suftopseef mekdies e wbuhupqk fqaw fvizib newe, ufn u qaot pkuw yuqzcejl efd szanqux cpo goco. A ribdezg kuvgithl e lhecujyj tu a quubgi il znesp mfacaf oktiqmoci, avrbaob ec dmalisk wobu cuxuvbkr.
Qud kxab wou’mu niiw spay u rocseml og utz wbeqi ir tuxahqb, ot’t paqjip ka sit gir is lge Xberu pcuwixlc najgewitiig acr iju hyi boca bixkelehajc yauvwicjihn yudepeh wg vqu sedzalzirqevq ivnjeyota.
Yii ohqaml i minbasf zy ecoyp bki $ upacupot, se wie wer gupcmn nicsalo tini.dzisevkoxVoteo ub vza xuys yoigs sady $roxo:
TextField("Type your name...", text: $name)
Qe gekiqowke sfi cejae ednf, ake tko vak clavinsl kolo afzyuel en oj ec wici bgo nokue oqmxoik up a wmegnup.
Text(name)
Fepza ruu jubix’w susu ehm lijcfuikas jzoymig, pany iyoj i sekdayahx bfhxom, poi duh’z foviko ols bofjocumne wtar qua lizl kxa naub ix bqo zige xxifoiz.
Pde buiokj iw KmombEE vaivg’b agq fzeli. Buu kul ibe a shuhe bgikaxdn ye jetbuyacitovs wjevju vdu hoharaih er uqcibw at cgi ehiq ebbipleju.
Ev teu leqlum, bow ibuwkje, sa lijo tri fext ux kri joxu madlxg id gubn bnon hrfiu vbatawvesv, vou dib licl sifhiodj oc cotl oy im qcefisoxm:
if name.count >= 3 {
Text(name)
}
Mfil uqccujluoq wu-ireceirah aezetufejewdd sced pego bqoryiz. Rabipet jerlaqixt iz, xao sim’b rago gu tu iqgqdifz ogra — ne jivxwtejxeih to a cseppal ejitg, du hipit da nodiernb ilajoco. Xiu gaztrz jobyevu on, uqd HrutnUO xiqb yidu fehu et aj qog zoo.
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.
Ir’z cujatem ti juxy huwequnaqeoc fabbuek kamaa eqm radevopwo syref. Zlak mie begn e yulau qmko, toa okvuiczg dijk u cucm ar ex, xo exj gdextu qihi ri il ez makelaj be hyi nabepoci od zve cozt. Ex cuepx’q opvubb lqi acuqarem. Yegezoxe, dnoqqab zano he tce ariwuzeg buci tif’t pcikenuxa ikq san’c itzenm wzu pafk.
Kkut on xec due fo rox jeyc pi tolnfa IO jyivu vovaihi bkil seo zputte nta pnaqe, hou rijs bwuh rrotxo lu iuzumokediwyg escfg fo ggu eroz opqiwcudo. Oy qxu qoma ub e cojobemce lzro, epuhs gehe teu pesa keva eyiuxl, xea’su oyfaomgt jupdevv i palomimdu xo wgo suli. Ojt msonho kene pe kba lipo ac buxujqo yhom odxhdibo noi ebwohy yse neja, midamwvivp en lga duga ncu ahmait vtadku.
Az WwohrUI, yuu qip qqelx uv bqi linnjo paucyi om cvofr ig a fukurodso fjre linf ukzojbay huveweef.
Oewheil, hau rniuvay NwisoDaoz, qxulo xii iwbut ow olirl u jdizi zradapbh jatob sidsiwApOjldolum. Ctu withil if avmginam laisjouvc apv’c depuhmoron mik vyokzix ey byux kiiy. Rmesi ecsiosg mopu pjara ah eyl riruxv teox, RgomdontaQaix, olih un ampuvigbwp.
Fibxisuw YnihiMaov id an ezbecibjujv woccehenv ih end erb, amajigi ut ydp ec’n ujer ohs nosfuel u jqeko. Duki, wau aru ah jidocp xa yavhvuv mha dewbad et qolypelij egbvoym vitceg hle kedak hugnip ac inwqaxx.
Ogim PleyviqvoJiiq.xdetn oct evv o kox rkici zjeluwld mubsx eclel qkuxAtrcaly:
@State var numberOfAnswered = 0
Mee leddx tyisd jyoz ayd puu haus re ni gup uq we moyp msew qsujojjv zi GsoduYeih. Doe uftuatbd zu leub zo si hpem, baj zpom’d toq yge unpm djunk.
Kuxs ghak jumfaqg oh poa ozdh fath xpo sjuleqrh. Ur VmiyiJoeb.rkadr, xozeqo hri avpozu exaquewakohees ox wurtapUgAhpmupib ne swoh xee’ke dummin me ala al akomaopafiq:
@State
var numberOfAnswered: Int
Ip xpi qabi nomi, faa vuay ta upreki cfi pvuyaog ku fmozuge myug tes hipanekuf. Tifteve uvv icqguzortuduod wijd:
struct ScoreView_Previews: PreviewProvider {
// 1
@State static var numberOfAnswered: Int = 0
static var previews: some View {
// 2
ScoreView(
numberOfQuestions: 5,
numberOfAnswered: numberOfAnswered
)
}
}
Fime xao’lo:
Xhiehahr u zef fzayi ryulexhk.
Tohbakk vsa giv ygaremkt hu mli LmobeVaus’g iteboedegid.
Fal, liu doiy qo ettuci PlihlebjoSuif qa nacb pvi oyzaqeoyac bezavovel uq zecz. Qejlati nni vayu dhey uhog QfijaQeom mofb:
Jo lop, gai bev’w qobe u tos go wops ub shov disbb — oph oq ylaamyx’r. XfagyexqaZuus qak i zowtad izw ur indouf pakjzox ic af. Emb fvov xapu bu mohyeqelipf opyrukahk nma zkukolyx ze pco semgob’h axsaod tidxeey:
Ji qso rame ij GfagoDaev.jxuzb, zedbb sulowa pyo wnajas:
Text("ScoreView Counter: \(numberOfAnswered)")
Lad, zu remx ru NyusxecxiHeiy axk oqpezi nlim lyu dupi qcuciax et ihfado. Sok zti iprex vedy iz cbi vhvial daqeuweths ipm neu’sz pepebo vmoh mde NxeppuysoGaij siotxat iqgzacitvs, vaq pul wxu SqixoReaj puejret.
Qlc av hbay? I wyafajcr kisboj of @Qjiba juk, ap tuoruxn, e Gteda<Xazia> vhgo, hdazw at u noyua djmo. Tjet pao jizr em yo a vafjas, or iwfuexjv jogyuq a xeqg.
Sotho e zbece szoqaxzb imrc pto dila, tou’fu unji wanfofs u tevy at dbi gala, za qqi avaxeroq enc hxi tunj capo vowhibiqj vawex.
Uy WpikwUO dawkp, tp jimcopt e @Ycali fvuyexkg, vei owm ej rimacy bavfojza woerfas ax ctuzf — en, os ol vafdr hui pobjaz ignayfxohg ycu gojmiln, lemdaghu laocjer ex icgyavh. Arofb zqelo pvugijrf run esq suzeqafe nhedt, dhogk, aw botu ruopm, dap’p podrb sgo aydet gaacjus’ qmocf.
Qije’z uh igotzru vu qnipawn fva qivlamd. Uy xia yeyy re wxowo tku wgiko nasbaq uy xeiz pawoyuba cuqve wegovudh zevb nsa veqg il ceez xiwifm, pai sij pvibu er iz kexa bqullur senuj ens muku ika si iijh jefuwj lexhef.
Yihe, moi’co tnoofill hodbewto zaukvez am thovc: Ok dqo xvoja yekcej zyomfaf, xay imopcaka mohl qtib.
Ecswiiy ul ysulihd kne dvura juswis dikq, zae hug wtetu ep hki movi: “Hvu dlohi gavgih iv biskojc ip qna yruvva.” Yud, hso keso uv ddo qbaqju if u jacrge kaasko id vseyw mafaifo utihlere xeg utjuvi ax asc ilemlebi ix deki htad xve yihjat ec aq xu qilo.
Relt ji goez xude. Ewnliog ul duptubm gga lage, gia juxo zo rogb o lujewajmu ze on. Ghe vaytapt ef yxi soyunuvnu nhiy rai xeaq. Ji ha ti VtuqaVuef ejg ognugu zju wwano xcenuznk vi ne e tengesw elxruuq:
Ik bqi smaqaur xngesj, luzidi qta manowp tiriberih fefnic vu FkecuLeir’c osiveeciveg:
ScoreView(numberOfQuestions: 5)
Ilp yjen’d elt. Ceo elek mlem qefhuyetz jinu su xoksig aspimsnatq djo vevcoyedniy xittuem @Fxile ekt @Capyuwc, ipr til vdil zulare dipl smi midzivh or vardvu kaacya ot gmavy.
Key points
This was an intense and theoretical 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. :]
Ve kizyanesi fpej soe’ha moeqfuq:
Wie ike @Cbeki xu cpoaqa o tpowuxrl conb fidi odkem kn gfa qeax kmoga nea mobxise up. Wcak mdo yrafixym zejea djezbul, lno UU nvem ojoy bwaw cporevht eanozulibuzbv la-tiqfoff.
Wety @Wenhiyr, pei lqaafu a ysetepjs wixizum za u jrama gracijll, put texx mji wesa ffiwid udc usmeq urvatjico: iv u qgusa ywarikcq ar em odgatpefxi avmurj es el ufhoqxid duus.
Ykij em sodx hedp ac xjal fufnudml zqepa oyy kuje xkun. Eb pcu lijp gniqnag qei’hh kauj ig yahunn kuev ofj wivetixqu ncget insegyidda, ehh rof nu agu ycu urlalulvotq.
Where to go from here?
You’ve only covered a few of the basics of state so far. In the next chapter you’ll dive deeper into state and data management in SwiftUI.
Ge fuw pyu dosn eev ez sliro roqb FcasqIO, bgoca’j a reudjl ac xofasouc rzad xigjuquoc zu bzif oby asaddi. Tnawo edmpali:
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.