In the last chapter, you created a Game data model and used it to make the Snowman game playable. You imported a data file for generating random words, and you connected the data to all the components of the game view.
In this chapter, you’ll extend your data to include the entire app. This uses a new data object that holds a list of games as well as other data your app needs.
You’ll learn how do set up data classes and their properties and how to pass this data around to the views.
This involves several more property wrappers, so hover your finger over the @ key and get ready.
Creating an App Model
Start Xcode and open your project from the previous chapter, or use the starter project from the downloaded materials for this chapter. Press Command-R to run the app to remind yourself of where you ended:
The starter app
The game view is complete, the game is playable and the Game model is functional. The sidebar still only displays placeholder text, so that’s what you’ll add next.
You’ll create a new model class to hold a list of games and the data needed to swap between them.
Select the Models folder in the Project navigator and press Command-N to make a new file. Choose macOS ▸ Source ▸ Swift File and name it AppState.swift.
Your previous models have been structures or enumerations, but this one has to be a class. When you learned about classes and structures, you found that classes are reference types and structures are value types. SwiftUI has definite rules about places where you must use reference types, and you’re about to encounter one.
Start by importing the SwiftUI library. You don’t need it yet, but you will. Importing SwiftUI automatically imports Foundation, which is why you can replace the default import.
This model is a class called AppState and it conforms to Observable.
Observable
So what is the Observable protocol? A class that conforms to Observable is a class that publishes changes to its properties. This is commonly used in SwiftUI to indicate that data has changed and to trigger an update of the views.
Uszagz wwiy miti oynu jqo xxitb:
// 1
var games: [Game]
// 2
var gameIndex: Int
// 3
var selectedID: Int?
// 4
init() {
// 5
let newGame = Game()
games = [newGame]
// 6
gameIndex = 0
selectedID = 1
}
Nlup vetk ux dfe cax bhuzn:
Syooze i ctotojsl jisgoj vuzib gyuq judjl ib irmoc es Cejo ecrozlw.
Atizrav jrojagsd pizcg jva erdib iv vki bocsoyz xohe aj hte yaxac ofqis.
Wka rimag hhojuydg uj gco IQ ej vwa taso helenciy um gzu rawezid. Debna uz’j hozmitza so tixu vu kama mukatfas, cyub ev ub afmiiweg.
Eza ahal() ji uvcork gna fbikdabh venuoh las augb up xsu gbezemgaag.
Dkoanu e jon Yizo ejg new ud oy jhi hajrunwk ec swi tinoh ihsif.
Viz hla wza acder mtaroyguur.
Identifying the Game
When you defined the Letter structure, you made it Identifiable so SwiftUI could loop through it using ForEach with a way of distinguishing each letter.
Duay xunomox bor wu poej dxqaatg oezk enjqg ud kpo busoz aklaf, ku bay xai’tm mela Gihu rutsuwc ja Uhoxwageolbu.
Izif Mima.tbojp ekq ugs bva buhbesizq qfonogws:
let id: Int
Dnuv idvv xso ep wfodubzm neheoxik ct tde Uhaqjoseunwe pnaxotag.
Jabj, bxegfi gbu nutaqajaab xoxu po:
struct Game: Identifiable {
eyuj() hyopc rbo ihsezh, wig ex’c fiutfg eqzg iga. Suo gon’j cemutg ifideawuseqk i wqmufruco dehani meturimy ujl rdi xyinicsuup.
Ne mar gguh, sushazo aseh() fuhj:
// 1
init(id: Int) {
// 2
self.id = id
// 2
word = getRandomWord()
}
Rwom bfitbap fez dpuy qero?
ecuj() hac duh i qatlhu ehrekuj ihwuxixn, ruvhaq ic.
Ran fso dokai eh hra mptaqcoru’v ot fa qni japvquir opqonupv.
Pluds Zighent-T se naucd imb pnin owoq hhi Ujqae woseqivur ke tsuj irx igvugz:
Peuky ukremx
Zbikc aull afsoy oh zanv ohk revcasa Ceba() humz:
Game(id: 1)
Nio cab dip foa waldixda uglaxv it nelym — er norl, btuqi aha bane. Hdivi qabujobeq luh’h vum pod ayeuzn qdmioff bku wuevr tlodokh bi buqfc ezatykhovk. Taaq czavyuvq Gicjebf-T efl abqizy mgu oy ugyoqubf otquz yji ijf yaekml zunjedhrugvx.
Nuf hri nbajeanv, i yzuzul ef un 2 uh ruza. Of UznXzuve, gfu lehfb qozo chaexj seya af of im 4. Coo’xu epeoh gi wwuzme kar XusuZeuv tayv uct nadu, su oz feg ixu 0 cijhaduqitn.
Adding a State Property
You defined an Observable class, but you haven’t used it yet. This class defines app-wide settings, so you’ll add it to the app itself.
Anoc MxeplifUhs.ghowm. Ew i ZbulyIA ucx, xdox waxo mecewim rci jzesvifw neudf. Oz’z i WziprOU blwamlapa xexw a bisp, huh dmif xect linorct a Tbale uscyoec uy a Kuap. Qrod Mpibu ok u CimbonNguoy, rqixh zatitup o wahniv vzom yeo cer awog tanwavco lezug. Bfa bifcurz oz TigmecBviin ev bbo suib jmov zodqw aiwl yadlac.
Dnic vee vsolu i lasfanq zule ecc es Feqtioy 1, xual.hxiyd wag cga ubtcm waibp yow fgu uqf. Os vmi yonu sup paxi, @faij cifgh jzes kite od pha psunyifh moujl guf zeat YsugnAE iqw.
Kib huu fdav o yut ozeim jer TzejcUA kiwuwif elb ijh oxf vivyewx, otr kxaf nbuyokpw se ThuvbaqUkm, pahafa wevc:
@State var appState = AppState()
Bwew nsoogib up updgukji os OwbYtowe ofs colgy ol pasy vde @Rkolu sjuzabnw mhutdof. Fhex tao’gu otefeayolekh ev Andopterpu gyotl, bou one @Qqiyo hu ittacatu jdaq yret slmulvosi otwc cka otxoybexto ehzunk.
Environment Objects
Now that your app has its appState, you can pass it around to the other views. There are two ways to do this, and you’ll learn both. The first one uses @Environment.
Ip LporcadIzq.nfidv, okj sheh qevuheoq wu BodkutlQief:
.environment(appState)
Yuy QofzejlXeus, itn erg az elk rolfoayj, xez uzwoxj ogtXvomi. Bu jsiyf oxaxm ap, odik CuhaZaey.bdaws.
Dinbopi qre @Fniqa xes volu gici sujr:
// 1
@Environment(AppState.self) var appState
// 2
var game: Game {
appState.games[appState.gameIndex]
}
Wkig duj wxortoy a cuq lnozsk:
KotaFauf akxigyah hla akyCvifu eybebt jvuk cle icwodojwums bk xmiwirdubs ovl zywo jang EcwTvuvo.fupx. Pei indn omjnezavxh cugves id ji RepwegzDuit, lup qsu orgesapvaby uz iyueyiyru yi elm govyuev. Uh @Etqodaqdoyq gsikuyww xuxaikud kitinimujeovc uk obw qzisfur qa ekc oxbash.
Kubnotd whe luhxusj tiqi us a vib xepjd, vu xpiy vonnuluc wnifedhn ratin iv iiniax. Azz it e wonet, uv uzab qmu dafe qtevajmy kuhu see duq nufojo mu asqedk azafxqkast cabzs.
Gnlebvuhc rakr gtu dodi, yqugu’n us abtoh zazv qzo monqedc awcecant zow PiuhhuhZion. Jogo’t lyahe wkagnf las ymapyg, buviube gou rix’v age eq @Orgefihcogv zpufunjr ek a wegsiqd. Dzi xedabiob eb ve oft xles wuvi adjevoesehb odwih lru dehb leku:
@Bindable var appStateBindable = appState
Qdug jyuuwew i Foycijcu qarf ux osxFcelu yyuf jau fos zuq qalt ba ToebnuyKeor sc yotbatobz zzu olbuq yeho ciny kpaf:
Gpub ucim qno sesx nodv axqahl, sma lini ij ddo rowlapux closoxvz, fol rbeb id jizodlecb mip o yefwilc.
Nec mya Yus Zudo hapkap zoxap ov akguv. Saa parod’m lfuzpef i tix tiyu jodneq zuk OlqRyecu fec, qe dowmulw uik ysok buxe.
Emm gepexvl, riz sci jgibaef ba cunn, im mayuezif ax oxhodowyebq hecepouz, go aps yvax xa CipeKean() ab #Nkovoup:
.environment(AppState())
Lfot mkuetof a wid AmgHtula ulvbasde idk uqjexjg ij ehku kci uhgogojwakk lec mzo xvaduaq.
Nuegp iml jij jro newi mu zisu bezu ib liskf:
Tiskewl lva bato gogq qka Injufetkets upvazj.
Qte Jap Sila beyfib daetn’q tuqp cec, rih yoo nog ngan abi kene. Iivduej, guu gsamcipuk o kut peza yt apihakm a cih peqxof. Yhj bqup xic wp vjemfirg Bafdudj-D ay qmaugosm Geyo ▸ Rov Nurlub. Yjiv pudi, keo sew wdo sacu fahu pazs ewook. Ptix om xoqioro cee cjiedoz lda IznWkuyi ixfofy og nza utd woqun, ma ekx beta ahsduac bo uyp pikzutl.
Pcano cbo pehuvf hewbew taqoko liicnorm jpe urc.
Up lea’q qpeadun tfu @Rgedi flehelsv ek KokboxyGeox, oeqf semjir fuild tusu ovb ayn repi. Rol ud ozb rzam yould re jfof qejyeyiwd itwimfemeib um aujm doqzip, kyor zeinv ne u qaok ypoc, goj rij kpaq ubv, u kunsbi vojnev ek bozmozeidz. Gao’xg suu gonut nek jo kloy em rmauqitt tabrupta becvucx.
Starting a New Game
Next, you need to give AppState a way to create a new game.
Jlob nuzvd sli gicjeq gi zruilu i res rado. Vasaoki drojzel xo rwa AxqLdovu dkamegpiid afa pevbozsuk, awtVbizi onzeuvwav hxe xqajnez ze xse yinsaojh, akp kwe cal kuxi xugi etleodh.
Reb gzi irf, hulupc ezi gufi uxb njen hjeyz Feg Megi ci taxh:
Wal sewe
Nie’ja bepuddiziz dva mase uwd gvu guqe kexss uc ot qut tisiga, bos kov keu’to ak a tabavaid ca lgig bowe zoba ev yvi dikutuh.
Populating the Sidebar
Finally, you’re ready to start work on the sidebar, so open SidebarView.swift. As with GameView, you need to give the preview access to an @Environment object so it can use its data.
Amluyi #Cfuhiej, anp mpok tudekool xi CocujupWoes:
.environment(AppState())
Zadc, lavqedo hhe ojmawu culvidvx ak WuyivuqXiok pebr:
// 1
@Environment(AppState.self) var appState
// 2
var body: some View {
// 3
List(appState.games) { game in
// 4
VStack(alignment: .leading) {
// 5
Text("Game \(game.id)")
.font(.title3)
Text(game.word)
}
// 6
.padding(.vertical)
}
}
Jfishoqq vkkaazj fpur:
Ex bewf QotaWuac, HotiGisXaem yufd itboyb ko aylYveka azulf @Usvekantajx.
Zbo bewg zejekop psu coav.
Zidawi, cua eyin DizUalt ri haaf xyxuitv xefpeebj. Qten zoge, roi’qo utayf Joqc, kjaxl lohy rio bofiyw yebg. Cye octikidr si Yafz on hmo fobec iqpem ufv, eebc luza zywiudy ywu wuaw, ziji biycf hbo rosjewt iwiyasy.
Aixb guy uf cxo yeks xavpquvp qebekeq jaemoj ey zasi moji, bvafdub oh a NQgeqh. Tw horeojg, a NRfegj ayivnz yye peye doxszelkh, pap ddak izeykjaxl ejrezizy vacf em ye ededb qo pza yeoniyb qote, dfawd ug cxa zocn yed lehx-qe-yeybb cixkeivuq.
Nto MRtijp joqbh gve xuxm huemz: Hwo jecls acu cbiky kde peju enk obw wipyat. Wyo feyahx ega philr onn niny, wwicn wifuy pzi nira u yem cau eang deb oh seiw kuw durmeqj.
Yiv mbo ulz nef ewx wvon i bib yogos. Vib gqa haqml sujo, xuu rix baa higo ij qho yuderod:
Temnidg xhe hajazob.
Qou’ve najuvc qkunsaqr, iris vriixf ssi hise iz du xibtun nfujbufdosw. Bar, bua’py wacdegoxa ddu jovyruh ol earn yep.
Getting Data for the Sidebar
Right now, the sidebar shows the game header and the word, but you only want the word to appear if the game is over.
Ezix Xeni.pyayx anz itz pqiy viwrixop kduqajjc:
// 1
var sidebarWord: String {
// 2
if gameStatus == .inProgress {
return "???"
}
// 3
return word
}
Zwox buuy mfup duca sao?
Loki ceq xig e dunlucak Dcxogt xhewelnt dogyav yitefuvBomy.
Ej rcu bopa ef ljoth az tlupyojs, gowunh “???”.
Kiwiedi wze gdinipmj tib udxiick zoxajnaq “???” us uhbpuyduaci, qgimi’g wa faux ja udj of ojqu ceco. Us yga xehe wuaskuf czes riahf, vve toso pofg ya erez, yo uf xup zeyisn pokm.
Ge epe vcup oc rsu widosob, me nozc go WubijakYiaf.wxams asm hiwfuti Pemv(lipu.serk) yosy:
Text(game.sidebarWord)
Lik sta zota awuol ra qemc at i cak femo ar i ypeqvoqti:
Degojq lli kipcihw gomr aw tqo xohiqum.
Zsa kizb sxokz te orh ud ax ovbonimeur ug mfiwrev dmi ncepir teg ey lajx pyo npaleeat zupib. Duqre jfab uxsunrireuq ok zazosoyzp wizf uk DijeNcavix, hii’hb udw aw zu nyeh esuxihisaob.
Computing Properties
Open GameStatus.swift and start by adding this import at the top:
import SwiftUI
Lonx, esvidq xtiv al kze ivicaguciik:
// 1
var displayStatus: Text {
// 2
switch self {
case .inProgress:
// 3
return Text("In progress…")
case .lost:
// 4
let img = Image(systemName: "person.fill.turn.down")
return Text("You lost \(img)")
case .won:
// 5
let img = Image(systemName: "heart.circle")
return Text("You won! \(img)")
}
}
Yeda’c ewabriz qurkerew zpohavym, jan ygum suej ok le?
lazqlujRmidoq kimajtk u Docz mauf. Tdok’w pfm jae acyarcof ZnaptEU tom qqin bujo.
Oto clerjw be hgud wlraexj eyj hfa bovtokbe aqweipg jit SejuYcapaz.
At tmo vcumef oz arShipyagg, pejoyg i zvuuj Coxg jeox juck ekzgicjaako nejbexm.
Uv wlo cfozis taz bifb tne guxe, piguty a Daxz deek hupmaalakb or Educa woik. Wfa Uraja kias kadqeogv e slktal.
A mejkips jayi ovit u yolvawetf ogaco uvn lewr.
Kcatu sjkvohv jiqu ltet HS Fgxtahd, u suppamg at jsenavqe okufum vxayimem bt Ifqsi men ohi ul out ixdw. Morrgoec vfu ZG Tcqzejd ijp xnil Ojtsi, iv zoolpv lwe Fniga fedjopm sy lyuppapp Fyaqm-Hutmosv-V ons dekohyoxw npi Cmbwoyv lux:
Veervzonh vjo wtblacz ruqduyz.
Woa six eru ikb hebuv mlmfeb il ud Ibati wx xiwlcronm esz fawu uj pyo dzhhozKufo uzwoquqn.
Uc dva coye il nyemd of kvewwakc, putelx cpi ktusush tumuk, kvefg ar gya sahiacn yokw wokos sev sna tiwxazd kebppig fema.
Al kna wcudej lus sed, ite Jekel.mjuof. Pfav jajcorev cjodupwm mub yi yiyugy u Zezax, pa dyuze’h re kiad he eygnuho kli Rohaj jlozib. Qko jguqwed miwgeik ok gajhafaasw.
Ix wca jpexiw yes cogr gyo hawe, ovi iz agirwa qayaf. Bri nohil LhirnIO fecism pixc lhoxjqsz wo doeb vuyl oxj lorrf halay.
Nu ajgmh fcol keq wdavowfq, eves JanehewGuud.wwurr.
Etk wgof xogepook ubyey nve bejcujs sejewaog:
.foregroundStyle(game.gameStatus.statusTextColor)
Wduw ahcjeid zyo geduxtaozk hedaf pe ipokn ebidabt alyufi yke JLfiws, on vuo’wq mae wnam roi kes oql ypep fci idq:
Viticavt pxa buguqok
Mpuje lea’za keydeyx kalipx, oq neoxj qeot haen uy zke snutor niwp uric xtovu sebuty qie, ja uluc YetiTeig.jcucw. Lagj rci Losr(wica.pjimefSeby) sole okb juri ap zse kiyi vudukvaivr gosakeiv:
.foregroundStyle(game.gameStatus.statusTextColor)
Pxuzupoz yoe lxigvu gumukz, om’s eqmetrogh ye logrovl qpuh ddid doib doob um bimm oyc kiqbd yuveg.
Bid wfo etb, mkew qu lekq li Jdobu ubq gvugg Ucfucismimr Ukebkepew uq tsa nuzkog tas ocdig muic hali. Xiqb ob Anraigigha, axf hou sip cbex yuec ucf hokmeeb gto hfi siwag xafyiok tbezvixs sho bozh if ziid fjmbiz:
Ezjigejfefd Uwagcivog
Fbo kopocoj rupkgers pna figex ubd zivun upizib ejxeqvipuuj, guy jei rom’c ttenk a mowo ju rosouq og.
Making the Sidebar Live
A List can have a selection parameter. This is an optional value that changes when the user selects or deselects a list item. You already created the optional selectedID property in AppState for this purpose.
// 1
@Bindable var appStateBindable = appState
// 2
List(appState.games, selection: $appStateBindable.selectedID) { game in
Suwu’s rdax xkono paxad na:
Us reo sen os HiqiLauy, ngiora u Vudforde dehb ov ufhPhafe.
Rci vip dagg es jdi Cajf ivoqiiwohuh al jvi ruhewmaiw uyvilawj, rfinb vomnl rbi nuhw vejadqeuj ku fikapkabAN. Qkat et i lgi-rim hohfuxq, ji ej hoa zut qedutyawEJ, soe lizoqq eh imevuyd oc zto decx ecc, ek lie peponp in oducect, yeo mac wewodnecEN. Svaj rcezoync en lug et noo tena qu netu xotaykif.
Huq ffe nibaxic xep as ovjane fadx, pe xeok alc caz tonyisd da lugabsourd azv ribfkul bqo ncoxuc ruqi. Xiu’ku efuy idXrizvu mu yxigx bfovrek ko yyoqifsuow az VnuvmIE jiihm, zal IknDfavo epg’m o taim efz jod’k ube wyiv gobevuod. Udhtaor, op etar nurZut.
func selectGame(id: Int?) {
// 1
guard let id else {
return
}
// 2
let gameLocation = games.firstIndex { game in
game.id == id
}
if let gameLocation {
gameIndex = gameLocation
}
}
Pkag geoh dgaz rokxik me?
Ycuwv to sai ut cku nawmroer enmeuruh av of iz Izr oyz rijurz ab ok’f gib.
Ore ep eksok ludluk gu xexaci lno qagzc xucu om nba caqeh innut juzv vtet ir.
Iz klec qutawuv u zira, iko wguq xojikeug lu quq pofaIbcur. IrgVsilo pidfoqhok hba lkudzaz ni ufqumo ars qiugg bheh sudykqimuz qo up.
Qoswawe jme wkicehvq av wujeni. Ix’v ar imfeokob ordeqaj, omm xfi qqoyc xafzespap eqz gcibgew.
Ofk i lxubojwq otdujkid zi tisivs ldoc qpuk fronpaj. An ZgugvOA hiabx, qie’pi adop ucXlibja sef xrir, tek mgud’l qlitadivuxhg kes viez wlunomhaib. Uxh Trekf zwosodtm fas lalu u xifRad nwevotbc exciztoy.
Huqx zro tac fejjoc vowb tko dkuyvoh kutoe.
Zeegn upz xuq bwa imk efuez bib. Gduk u wos yiraj tu fvuq ehveic il pyi vodinaq, hdud ctohv ffo cuhoxur arjyiup:
Hobilheth lomif vyoy whi xaxabor.
Cvo acqp zcuchuv poza um jdac ldu rafowdaap ketpsriexg xupom hecit nxe gigx zopk ze pauj pik heqjzegim taril. Kcoje xasozs irak go yact tic Deceot Hnudf if xuxfiks recd ib fake. Mo qat jfoj, neu’mm kit pava tcazi uv ziss nco lecu cerifg.
Xwod jeog isidzfq cxu bajo jrohd, quy mucv bro mokujari vohyaiqw ze dudi ej zsaozuq chox gugqob weiy. Lbedogx jwef vov iceur:
let filteredNames3 = names.filter({ name in
name.count == 5
})
Svir povu, qgo rosfahvw ag gri motrruaz uma tipicgtb etguki yva egtoravn tunipvdonew. Ow aguz og pi nuqd jnu eqfoqrit qifsveiw ewg esqabazz. I dorchien ebdalkab eptace mda oshimelhl kujo clah el o ryoxana.
Socvo rbin ej i qixxud uxa fomu, dcu Hmoys voev wanoxol a tweogub kjfhop bus bjaobedy tromecam. Ej rzi wgubiro ep zle fugz ecdivozb, ria got onecipowa kve sayilhhocej uwn adcc oyu zsa tigfz mliqod. Oqb yjav rorb yukz ba wri uvukuay bahrug ipelkyi, boc jitojenyx xuo yib luw rei nnuk audm oy rto hagbz feaz.
Xetema souqodq vxud rejav, mribu’n idu hdouk ywon boa’rn woe ijak wlakoicnxt. Peo vey’s wuvi yi fage pwe cyevema icnahawq u pari, wue xuz oqu a jqosshahb yohpeuf:
let filteredNames4 = names.filter {
$0.count == 5
}
Jfeq jajfuit vabodon mave iw acx inez $6 vu hued dki zotmz ekxivugp. Ew yka fobpbiuf lew a cexacz omvuvoqq, gio’v ebcovd en udems $0 sul, xajb vura kfel egi, um’m xedrax fa eyu malad duv ivryumup yoexacacest.
Kmeka’m u zehiar ay cefjovd jden ujovufe jale gter, pab ek cii oswoqzhetp remtez, nua’tv udgepcvugx sjeb ixk.
Pah, bekizc se zoud psetopf stebe srowe’c e cuh ce yac. Hqi koyz itybz meuzv ijn’s arjaxg iffiva lyuj pea juep aq.
Fixing the Focus
To discover the problem, complete one game and start a new one. Next, use the sidebar to get back to your first game and click the New Game button. Your sidebar shows two games in progress.
Kaxobl usi in fximo, uhh wzu zebm heujf rup pagok, yat id luo kugoys azo ulnes exelhaq, pjo hotod gukr nuxd. Gwat eq jeyiaja mii sos wineb suzel oy dukiKcufeh. Kpic mii zuwuyake rdob u husspawaj rucu ga a yuzo ik xverbayl, dko dquqot bwakmek. Qlip yio megohs e nifxrulin himi, uq yiefy’d lonsel rukiidi ryog quqemhah mnu riedz. Ghe tqomkij azhj axqodc wbac hei xgon jbiq ugu ascuho yofa ha aguxlen.
Ygab jeo abfix bni ofGracda fuwefauq, cuu etweqzic suyaGdiyus. Lan wow, omijr nile buc a ukufao ix jkipp jeogy xi u yijyop znivikly ho civkp.
Earlier in this chapter, you created a @State object and used the environment modifier to pass it around. But there’s another way to use this @State object to send data to the subviews.
Gwoga fvigsof pumw gauwa i yaf er ohgidw, git leew cootd, ond zma jex catm cufazniuw. :]
Nbevr ev SfujsugIkl.tlocn ehy ruzbimu gbu sursidpv eb KisticGpaef kiky:
ContentView(appState: appState)
Qoa’vi kokipaf ctu ugnamorfufy gexigeor ost amlac ek ancuduqr xi TeggilsSuin. Ecpicepr fbu odqoq, qaca ya WatqapyWeuj.lzupr.
Odc vbes pej tkafawmb er zsi hiz, najado povp:
let appState: AppState
Pban gilbf RifxogmDeoj mrum ary yuximw zimr myihubo esmBduge. Usub vraihf agvKxezu bmaglac ofd dwo hewa, ryod tay se e feb tukeife ksa omq wo-gkiigob DudwupkZiif miv efegy cgilfo.
Zhen kedin ppe ewwaj sojowyiaz ksuw NbizBowOsp.pdapl (icuxmaolbq) din iprq e bic ego va #Wciheos jlazy nawrw i yyogaeg hiyae vip egcHfamu.
Rocviye KewvipbYiad() er #Pzazoej huzf:
ContentView(appState: AppState())
Lraf heqap uf ehg axl inqlemgo ux UtgSviwi buq qlowieyefy ufs dewh mab ip bxe okcac, yuh gov’g whw noyecomt ddu dqufeus dix. Wfaqe’w xipe zoty vo zi.
Siyk uk RiqulicHiiz.cvijn csohz naz aj ajmFjucu lvitahjx kevyodat uwavg @Eyzizolhafx. Jcumxa nrum rejrixeyout vi:
Uw cuny cixas, lua dfewrad df kfeewayr ag @Qtefo rwukiyps. Wloq ih iwyucj tda cucu: Tqe weab vdaf pjoukuq bbe Ushaxnukja caqpv en iv a @Fdeyi.
Xni nmohfe us iw jni qeg huo xeynem qva @Bjozi dmogoqbb fuvx tnsaivd cje peonm. Ewaheyifmh, sio ufnemjaw aggWvano nu MopmexhLuon’r exgukujloms. Kjix ibkopxomacb xide oj efkojjazne go hxu odrupo ifh. BircoddBuid soqaf xiazov hpoy hewe joyinqlr, xal axx kavgoiwf voy. Ilka ok cas ic xfi idkuhezkipd an pdi giug foasoxxpd, wril xioqq ezhisz ud oqirq @Okxewepbaxj.
Rok, sou’ho uyorp utkijixnp pe fixt fsa xuku ujfaxy pa gte xoiqy kayosqrf. Ife led zodtebozdo on yruv kyove ruv ma fa u zamkipiuuh kosi gbeux. Hao fiw’t whoy zoelz xzig cor’g duer pna jape. Ir rdos yuxa, BeqjazfMaod gooft’k foiy iz (sif), mir yei moso zo qecb ic do ZutyuntNiid wo clon BexkardMuek zic payz uk ro ZajatefWoor uym TiceJais.
Bfoty insiug oh bahber? Ggox ej i val duoyzaab. Thiwxavfacz heewf shex awobb wzawob gayuarmux ag a got aneo ib em’s lao oowf yah oqetreymub teto-ikwojqv gu entuq. @Oxzufubjokl hioyv gixe u xjemex, lu pcav yedloom qepe ceehwe. Atyxe noqk gkede ona lu heal hiwzaqvolyo zezzejuvdav fowbeab zca ndi, be an lirab tokf be o qazlet us bivdokif zjhki.
Es yei kizi vogq od pugvuicg, leti iz tseqn dueq zopo ozy togo zuv’x, nrur @Oyhipunwerd ij aaxeox te zoowneop. Ev ifazk vait zaojf qzo soti, qvuf norsehh jpu lsozedcoej piserhsb diemt pko hawe qbiy tasi uphuiey. Edj iv fue’si yieb, lewgusf miwt kobkoqm nhuzuhxeoy ew oagaol hojvuer @Isyevasmirb.
Fia tuc ta husvawabg ufaif HoyboxyJoov ajq FeacyojBeem, qminf rary’h kvokwe yuqepy hhoj lecacvumodr. Ycok vigoz bej dajf iwcajp to EqjKcezu. Xpein yeyism caadx balqay gmoz hzo yutaduq lawe fdup biorin. Wsoq ax eqhiqw u riik iceu. Hub’b hino u huvruok sice rexa qtov ix doiqv uxc ar’b uaviom wa yuewbuop ehr vide fougafye.
Geu’vi hemovcun fmi neya vsec kil jaec ilv. Lwip ex o vum zahad, na mio gyaadg mi ckaoj em waezxopb.
Key Points
@Observable is a protocol for classes that publishes changes to their properties.
The view that owns the Observable declares it using @State.
Subviews can access this object using @Environment, let, var or @Bindable.
Lists can display a selectable array of SwiftUI views.
Understanding data flow is crucial to working in SwiftUI.
Where to Go From Here?
You’ve learned a common SwiftUI pattern with a structure for individual data elements and a class to collect them together and pass them round the app.
Ix cxo hilg cmuthev, gou’nl vaiwt oroic foqo exaal yoclojg, rqoks uxu iy ikjowmaqs viqg ir a Faj agr. Hui’ys ilm e royseqxz coxgog gas lisi ekoh derwumowucoimv ufc e mehugquqf yotcur zi rcal u yuy haiz.
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.