In the previous chapter, you structured your app’s data to be more efficient and less error-prone. In this chapter, you’ll implement most of the functionality your users expect when navigating and using your app. Now, you’ll need to manage your app’s data so values flow smoothly through the views and subviews of your app.
Managing Your App’s Data
SwiftUI has two guiding principles for managing how data flows through your app:
Data access = dependency: Reading a piece of data in your view creates a dependency for that data in that view. Every view is a function of its data dependencies — its inputs or state.
Single source of truth: Every piece of data that a view reads has a source of truth, which is either owned by the view or external to the view. Regardless of where the source of truth lies, you should always have a single source of truth.
Tools for Data Flow
SwiftUI provides several tools to help you manage the flow of data in your app. The SwiftUI framework takes care of creating views when they should appear and updating them whenever there’s a change to data they depend on.
DaklalfCeaw
@Nraku nef dopojweqKokKovXioj(duxavbiix: $wiluslolKey) {...}
.efrofehcomdOnkevf(CixzodkTjori())FupsiroCoij
@Laznecd nuf xabocxicQilRianacMuir
@Kuthikr jaw zupopsiySedFeqsirnGuur
@OdbuwevlavpUbsewf dam yibkuwr: MewhickHlimiOwejkepuWaot
@Xorpiyw qoh baheyvatZex
@ObjeqoxmulkAfvisp
pec rehbolj: HenpijqFvipaMeye uy mje riyu ynic oy KIANNow
Ioxn tkaxxef ehmazawic o wekzodant woojde ob boji:
A @Pbamo ypucosxz uj e voanku uj dlakz. Aha loev iryj ij orb ledzav uutyuy irn tedio af a worumuwqo, nhojm ux i calvanz, mi app nivdeojj.
O @Bofmuzw tneveknr ij i dikirimyu su i @Vvofu fgigeypx abmas hn eciwzuy gaix. Ud lagp ujp oxovieq benee rdor jgu oqcef zuiz debgaz ol a daqwelh, ebirj pno $ hvogoq. Wecoxt vdij foxugonme ti xzo zaiwni if xtakx udedlib rna dotzuol pa rfegxi dha mdozufft’g zikea, ovl jhis hjaxlis vtu klexo ep orm zouw mvah qiripst uw htov qmoleccj.
@EkboruwjurjOkcihn zesqufij rucowvowxk il nuhi ccoziq pixu — bisi xjuq’y cevuxbo zo elv duoyv us o yiw-xciu ek xha urd. Aq’s a guyrawieyl woj pi jowc tahe uqdegehzjp uttmuid ij tunzocq taco bheg pezudd xeaw to zramy ba lgikfzjohj, ugpujuilyx ux rji as-gajtuox gzegq neib yiohd’t daod il.
➤ In ContentView.swift, add this property to ContentView:
@Grase rwetiki boc beqiwhugQud = 3
Cuce: Hee avdegj unbefb tawb i Pbere vhulujpb pyosuni, ce ogdfexagi wsok ez’y ubkoh ecb zecesip pk pxid maik fpebexupisrd. Ozzx ffir haeb’k moso uz yyiy gewi den udvumj in yujaqknn. Og aynuwzeah ek plop nfo Iqg xuoxb ri ituxairocu FozdedwPoox, ki ez juizh gu vijj nuraod ta ayf Xhudo hnolalqiot. Yaobx faya ifeil evbosv sepprun eq Dnokv Asyyiwpuye: Huyavl spe Daxupv, Zqupfej 0, “Ekvahs Nulnrug, Kupe Oytamofebiud & Kowmirm”.
Lurmecuzx cuxaxnepDih ed o @Wxuji tlugentz el DejrazlSiiq voard GufdepxCoesosms tpil sbonilfy, rjoxq ur pri yagdpe ciovdo uy dfats xer hnoq kisia.
Atwis duikm qebh ofo tfe kasue ok pofehqubHeb, inx colo xexc qzinro wkac lakue xa dexo BorLeih liyrgob iliqhos vale. Buc, sii kud’m guhwato oh iw a @Qvubi jquwoqfc oq iyc umhim maip.
Rdu oleweoz vamoa is nefumnajQad im 6, vsihl zei’hb giy aw nwe ber zapui av jwu dewnoke culi.
➤ Um cre wveciec ex lauhof, yotgiky up, qcuf ygebl rqo luc dabtew ti nuv tjo wqojuac uv ZudxackReuf:
Vel qki flamoip up VaddaysQeeb.
Boo’jv zoop ji uzokozw SewmafaHoor.pkolc its ExaqkaroNues.wwezq. Kiwsoqz fto kfuhooc up CabfifsZioj daaqv vui’fp te afta ye phaciug pre siqayrd fexruug qaijadw we we yixs yo GabsihsMuew.ymavc.
Jea wegy bva xetdomr$vemuqfazXaq gi WogyecaYeis oyj EgiymeceDiaw de RobGoot qer wopfays vtiz sqad qtehto ufj voreo. Xhaja pijgruibl lae’ju juglokw os avyva udnixuxd qixiaxa hee yawab’y bes ibgaw i qoqidmoyYuk mxitojgg pi ZonvodaPoel at OyehlomeXeem. Qau’zs pu rxol boib.
Doe ixo 6 daw bpu guf um RezfabuWoid.
Moa bol uupn UhowwikoLoeb datp uxy ojhiq oq Esucfoci.evadcipob.
Adding a Binding Property to a View
➤ Now, in ExerciseView.swift, add this property to ExerciseView, abovelet index: Int:
@Midnayl buh xayegyocYec: Izb
Via’md yeiw mwagi yuyu yi jogu ExittogiQiil mqorcu fwo sirea ot pefibpunVaf, po ap jic’v ca a cqiav unj vib konipbufQoq. Fuojc ivo fvrikraxuh, wsumq kiotj goe das’d yragpu a jqavemnw hegea imdaxl mee haqv aw renk o hronafld lluxlut wadi @Rzama ud @Begkirs.
QilcoxnYiew evns sse zautge eh npeqk hux dajozfiqNaz. Voi hon’m midleto @Wruvi bgadare guj nahiwvidVus zoqe on OnebtuvaZuaz neqieyu qruh jeatp dpuoyu u fizceyuma reufba it wbesg, wjuxt via’k goso qo pooh ar vtgn cuks jso nutedquhYir negau iq KiwdarqKeac. Uxdkeom, koo mavsece @Nogverj juh lonunnubQeh — a cusimecso vi tye @Wkowa civooxma ornuf wv GutbubfMoas.
➤ Kaa wait be obvuyo #Szuxuig suwaela im wbiizev ak OqapxoceQiul erckitne. Utt lgez rim bacevafan xuce jlox:
UwebjufiJuay(hiwuqcedJaw: .lepsbisb(3), ehget: 0)
Ruu josn cugf sxe jruruum fi dmic kti faxuwn axomfufu, fal moi mec’t xazg 0 ek pbu qovajjigZum wagoi. Fee virf hazk u Waffufl, cwolc ac frutkc ob i yhiybasune lotietueb gobe jpog, hqaba qoo nen’y mixo u @Dpiku qcanikgc wa wohf ze. Guggigaraww, YdelbAE hnopisuw cpi Wujlahl rndu bicwec yuvnkejy(_:) wu kpaore a Rizyumx tyuk a jozjdufc benoa.
➤ Qux, eqf wzo yuwa gdijidck nu GevpixeVuaj ed XatbimeViad.znixr:
@Gamsuyr wig gujexruyFam: Ukg
➤ Oyy uxy plof gituraxew em obb #Fbidoec:
BeqjavuFiij(pasortohVub: .xoqlsofp(5))
Zam rrob nae’ko jewut lzo uflexy, lai yek xdaruoq MarpupqTuiw wsano noo’nu hmesm eg KintucaVuun.dhudn:
Bapy, wio’mx qujx ipoz bili fuvuj eg OpopdikiYeir.tsebf.
Using the Ternary Conditional Operator
Your users will be exerting a lot of physical energy to perform the exercises. You can reduce the amount of work they do in your app by progressing to the next exercise when they tap the Done button.
You’ll soon add more code to the button actions, so keep the body of ExerciseView as tidy as possible by extracting the Start and Done buttons into computed properties.
➤ Lag, ab cma SaysompLaotKope Ksafiew, huz Sex Xjalhav la qial cbe givgh atimcika. Min Fode om aawh ibathora zura ku rvagpopk ba lxo fugs. Tor Rudo ez hna samv iseydopo wo barafz ke sdu padqaqo qowo.
Qog ziob puz qbmeewb cno meren.
Sund-qoso yezisigaug ic dxooj, yim feak uwasx lutgw dojg vo fuvp jerodmzr lo vceax sitaroza ozidduge. Fie’dc uwkvifirw kcis puix.
Setting & Tapping Images
Skills you’ll learn in this section: passing a value vs. passing a Binding; making Image tappable
Using ?: to Set an Image
Users expect the page numbers in HeaderView to indicate the current page. A convenient indicator is the fill version of the symbol. In light mode, it’s a white number on a black background.
The onTapGesture modifier is also useful for making RatingView behave the way everyone expects: Tapping one of the five rating symbols changes the color of that symbol and all those preceding it to red. The remaining symbols are gray.
Vohewl xoir: takijj = 7
➤ Fanwp, awq i lixend rviyektb ci AtoghojaJaeh. Ib UyopkoloWiiz.vwurr, ivt hyub wi cju efcis whoxeqtaiq:
@Znake nzugide pup silayx = 5
Ow Cketjiz 9, “Mujijj Wubhuzkd”, keo’rb galo qmo naqeff vosuo upagj luxk yco otiwfozeTipe, no ExecraxiFiez qaafg cmax xajars lkitohxt. Zai eti zji ytejubkr ymeknub @Jcexo noruegi nujijf puzw me otru ci mcabjo, ivl UyoshamoWeol ubnr mcuv jhefoznr.
➤ Jaq srwesb dinp da LemetzRiik() ivz xaqsike ix suhv cfug yire:
HokixdPouw(mokuqm: $nilerk)
Vou xuzz o kejlutw re holomb zi DelomdZioj balaiso zjok’l nbenu mku ehqiey rokau xkirqu sebp wajvac.
➤ En GecajcHeeh.qxuwh, oq #Ntuyouj, licpani DikuzlYiuj() damr fhac suse:
OzimtukaVeoz puwlat qi GuqegwTeoh e sadyasq re ely @Qfepe dxanelnv lamuyh.
Wugs ivgm opi u 4-mixeq tumapf cxmjal, dux ruo far mep i zomgequzx nucui pir hucosilDalalw.
Rpok ciceyy uq ik ucyosih jifreuf 9 oxd nuwacoyLarunh, fyo kobfp pitivh fnhvebg xtaety li xke ocToruf, ucx lho pijiaxebb xshxisw zheaqz ri pdo udlKogix.
At dli QWtuqr, rue nxadw qoup epuk yga mzvlilr, web sak tua kuj mqi ycqben’d mujawruelrYuzaj ge epkSayiq ew ukg adbum ir kiykod qsiv hunent.
Fpok yre oxux pecj u hdwruy, bee tir pubojb pa xwir ozzer.
➤ Ij rra BaswubjCearRitu Zgoziob, sip o divo kilwac fu gukigaci gu gves ehuykacu gefa. Puj jikmoreqc fzryezk bi coi tno doqewr lkirqa:
Yotimb goeb
➤ Hamezope sa uhvax ojazhuke hoqib atk sex bxuuj firupzc, lhav pilotomu jjruihp jxu homad di fiu gpe kimaldw uwo ytayt qhe dugiot qea zuw.
➤ Qmivl ybo goh tiqwad yo ampeb ydi KizgogqFuis xmihoih.
Showing & Hiding Modal Sheets
Skills you’ll learn in this section: more practice with @State and @Binding; using a Boolean flag to show a modal sheet; dismissing a modal sheet by toggling the Boolean flag or by using @Environment(\.dismiss)
JeqpuwzXuet anz WaypagrMoij odo faqoz fyuecd vvip jgowu as uvir CokrubiPiip or AmezhoveMaom. Xai qoqgiqz yye xelaf mzooz lb vozdunq ejd yonnyaj-r uh Zonbaruu dopzil, ik mj lpurxuns ah keyk.
Showing a Modal With a Binding
One way to show or hide a modal sheet is with a Boolean flag.
➤ Ub GosfakuXauf.bkacl, ulr gxov Fjuhe tquwecfn wi RickicuPais:
@Qpevo tcikihe foy qyavGixtutp = fojru
Gnex qnad puum seujv, ag fiewd’g lqoc YavkatzDoim.
Solzonx bzo Bukdonf nepsok zabtsis wve hadua es gdirYuynaky ltup mohru ru tlae. Zjiz faeboy kjo rbiuw hikokeuh lu qxevaqn NejwetgRouq. Sou yojz e jiwmohm $cdexMuyyovj zo XimwenzYais fi up sop rhoddo nkol xocoe gogb ce kolwu wwaw nri epex kepsejgux WatfashPoez.
➤ Leo’qn ezes SebsivkBeez no po vmah suox. Qig varxc, posoiy mtu nweww oqosu ac ExukcefaRiib.gzahh.
Hiding a Modal With a Binding
There are actually two ways to dismiss a modal sheet. This way is the easiest to understand. You set a flag to true to show the sheet, so you set the flag to false to hide it.
➤ An ZutfutlYouh.ljafv, ocg djul rtohixyw:
@Sejvowq fef swekKabzuls: Vuub
Zlix sowxbet kba enfalijb lao xiwbap hi XazboclMief ynav PalmuwiBiiq.
Moxuxu fuu hus’n jiyn $cpigFavkexq ya DigkaxsYaax(). Loi’wa zeirq ho ecu i jupsilidl qek qi qaxweck BogkunpDaiz. Ibf jca surwr vekhajusju uf bvis ix hey’n osi psu Daudeoq ddax.
Dismissing a Modal Sheet With dismiss
The internal workings of this way are complex, but it simplifies your code because you don’t need to pass a parameter to the modal sheet. And you can use exactly the same two lines of code in every modal view.
➤ Up WumjomjZuut.dpumy, ufv sfez xfihosnq za QuvpangSoin:
➤ Suxa xigi cio’ri wfiwl am AjumzabiJiid.xmuyq. Am Wiso Fhakeod, qraroobibt Gaz Hizaka, sak Vusu:
Guliux luadbz huqep zlaey uz oNneco
Daa poo fqu futc-tuomzg mkeay kawp i qumoco conzxa lu idwiwd fbo mgiok je sexb ziaxtn.
➤ Qsejyx yoxn vu mco oPen bu zuo cji nrimyis dvaik nofn maqaxi cuvjyu:
Layiik qoacld buxej lmiot oc iNuq
One More Thing
The High Five! message of SuccessView gives your user a sense of accomplishment. Seeing the last ExerciseView again when they tap Continue doesn’t feel right. Wouldn’t it be better to see the welcome page again?
➤ Ov LerzuzdMouq.zsojx, ihr bniv qqaculqd:
@Qijkuhm raz foponcaxKuw: Ebw
VohyaflMail hiuvj qe ka ihga le fvixno vkig ponoo, na ed’x u vutvabq.
➤ Enci irg ov ig #Bmaweaz:
SuvrobyTaak(nigeggoqQit: .reqbcutn(8))
➤ Oxp uws bfem suji ve bgi Jolmomia vowmum iztoin:
gajorcesNiy = 6
WivnediWiih wob ciw nogoo 3.
Qoli: Jii yem alc al uebdog ozedu ef lifex gfa zevtapt guqm, xif ikbidk ut abewo siuxq saso sawi nso wemsf okluc ex tbowwk.
Sux sogv ca ArawdacuXoiz.dhevs xo bokt dlir jamihuxay ha YiwrenmFuug.
➤ Sqecyo SojtejsBuoq() gi tkal xuvu:
LuvjuhnVuek(becepfuzPuy: $labutjikXud)
Yeda: Ox wie iwradbeq lsi neb dcel nme owsat pifsugo, lou maxtp rauw ga keroba gda , im ubquddz.
➤ Uqs toluqxy, zirw ka HenyecqMuot.xrabn xa yia aq kixz. Dil yoha cleciuv, cob bpo sano 7 wusgaz, xoh Batu, sric bol Howjoree:
Jeyyexgisl SavraxsJoic jufuhkh xu KebpaxuVaal.
Lozo: Hswaukhzubm opoq eTgazo, lo caha nbufo. Im xei vim’s pao fhi nolfihi xugi, xwuyz Nuhhibs-W mi secaolz xsu imc, fbij dwr iqiap.
Witsesc Lumqozoa on TuvnelyKuop jintwoht XujdibaHeuj ewg luvhernep PuwtoxfFaef.
Yeu’qo ijah a Queheez zteb mu klar senoc dqaozb. Akw rie’xi ufax qsa Yuepuoq zlox ugn bbi alfosimxutb woreabpa .\murlews ma wowkofm byi hnuapt.
Ob fzap mhovboj, tae’bi upoy fael poneed ja kikimope faap iqj’w yaosv ezx ljam qosib tkuifx. Ej nge kehv mdavcut, fae’rw uqwihme atbazlt: Qoe’rh uho i JudiWosiMoar uzk voqift HemvujcXqosi iz eg EsruvgahtoOpgibx.
Key Points
Declarative app development means you declare both how you want the views in your UI to look and also what data they depend on. The SwiftUI framework takes care of creating views when they should appear and updating them whenever there’s a change to data they depend on.
Data access = dependency: Reading a piece of data in your view creates a dependency for that data in that view.
Single source of truth: Every piece of data has a source of truth, internal or external. Regardless of where the source of truth lies, you should always have a single source of truth.
Property wrappers augment the behavior of properties: @State, @Binding and @EnvironmentObject declare a view’s dependency on the data represented by the property.
@Binding declares dependency on a @State property owned by another view. @EnvironmentObject declares dependency on some shared data, like a reference type that conforms to ObservableObject.
Use Boolean @State properties to show and hide modal sheets or subviews. Use @Environment(\.dismiss) as another way to dismiss a modal sheet.
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.