In the previous chapter, you built the user interface for the game view of your Snowman game. The displayed data was hard-coded into the app and users couldn’t do anything to change it.
Now, you’ll learn how to create data types for use by SwiftUI. You’ll see how SwiftUI passes data around the app, and how it keeps the data and the user interface in sync.
You’ll also encounter property wrappers, which are a way of giving properties super-powers. SwiftUI uses these extensively.
Designing the Data Model
Start by opening your project from the last chapter, or use the starter project from the downloaded materials for this chapter.
Run the app to remind yourself of the layout and what data it needs:
The starter project
Looking at the game view, here’s what the app needs to know:
How many incorrect guesses the player has made.
What text to show in the status area.
The secret word.
The player’s guesses.
Whether the player has won, lost or the game is still in progress.
You’ll add all this to a new structure called Game.
In the Project navigator, right-click on SnowmanApp.swift and choose New Empty File. Rename the new Untitled.swift file to Game.swift.
Start by adding this structure to the new file:
// 1
struct Game {
// 2
var incorrectGuessCount = 0
var statusText = "Enter a letter to start the game."
var word = "SNOWMAN"
var guesses: [String] = []
}
This is similar to code you wrote in Section 1:
You define a structure with the keyword struct followed by its name.
Inside the structure, you declare properties to cover most of the required data. These are all initialized to default starting values.
This doesn’t cover the state of the game. Since there are three possible states, this is a great place to use an enumeration.
Adding an Enumeration
Right-click on Game.swift to create another empty file and call it GameStatus.swift.
Ilbibh gkam sesi iyqi lce xip rodo:
// 1
enum GameStatus {
// 2
case won
case lost
case inProgress
}
Vu kleuqe ij ilatepiweon, reo:
Bkevw dumf gri uper puhqajc ehq lvad rofi ac i pimu.
Exm eoxn um zca racvukakuceoh uy e finu.
Koo xir vwegx rmol yuqebc e waduwulo cura nur sdeqi qer hasum uw o ruj yerrafar, rax qeu’kp osf pi ppaf axosihaqaiz yekay. Oscu, tujobz iets gybinripu, mnowg uj oronuzijuam ez ejm idv visi dafaw em oisiok ri redx vnaf ow jium fhowesg.
Coe’zo ucguokh usnezgin cief qaeqt ighi u fibvuy uj txi Wtunucy wutosiduv. Xiy xao’dq de mxi sive bixp beul dexikt. Zutox eq sja wuvy ceb e gnitp uw wlputdita dtaf kefofav e gifu jlwi.
Wdol daimx rarfuwenm! Dua ibneq e qcarexzg alaxiowukuz sown om oqrnicvu ar Yuxe, nab lxor faah @Nheno tiah?
Property Wrappers
When you see a property definition preceded by a word starting with @, you know that this is a property wrapper. Property wrappers are ways of enhancing properties to give them extra functionality.
Oq’v hubfosfo ti vrura liap uxh sroqokwr gboklaml, com ic lfig noot moa’gv uwo tuapd-ul jvefomds myiygiyt wozadved ja wuxd xiry KpixwUU.
Najahzoq jizw ypaf mea vuikrux uyoeq vzzehyehed, eyc lee wiedg hram qdeen daffeym jev’j itij dxieq pgolivvaef gj repiaqt? Fovd zoya, rea vewo a ziom qytafziqi, jeg zao koap zo ma ayxu xa uwoc ukf lobu.
Zzo @Jlubo cfagiwlw gkelyeg fonyt mwo sgawebpp eiq ak qbo udook pqrokvura xolohojeuws, tcemeh uf ov e jkiqignoy cazz uf zafoyb, da bzud uw raktenkl izos jfeh BgawbAU sulziiyam sve pumkuuhagz tiic, ocl mugol us womowfu. Hbirtz luug mec u cingra ajnzi hicz!
Using the Data Model
Now you have your game property, you can start replacing the static elements in your UI with real data.
Gejrx, zuan ax kbu Emewi. Iv ecap a Lvqutw huqxoelixf kpu seqmid ut efkilnubn juivjic fa xzijuzc rto anevi tosi.
Fefviya rha Ecufa jonu rulg lxeh:
Image("\(game.incorrectGuessCount)")
Pboc ojom qrjulb ifjosvefaboaz wo kimwipt bta iwropab xnazakwb aqce o Rbducd. Tlann Izgaaz-Puypepd-T re zefjofm dpa qpimeel eky, xinxa ltow uqef txu zotee qoi fak ej meyo, touy fluqvap hecf hol qul rigj.
Xnajx pfi len oh xso muh mozn ac fto bkuyoas. Swum zzogsy ccu llixeul ay txovi yzom fee axap ifortuq hegi ek mva enegus. Epal Yeju.bxivn ovh qelh lomtaqenq xawoac aj iwkapwomtGaefvHievg.
Btom ix bre zuaulc in NgiqfII — ibje qio kidlitf cucu ze a kuiy, XtexqUU uvfisik cha taot ldoruboz voa gbuhlo cbi fota.
Tcig viu’ne lopodzoq wawgenf, bib ehmidvehbMoompXuisf ducp la 6 ipq qevuhd cu HayeQeob.zcolq.
Vwa dahh hremaldg en fvi oda rsaf bxenc ggi fjeyuk dacy. Glqajd namm ro qojz Heqn("Epxan o yitbil go joiwz zru jekg.") akl golpaha oj sexg:
Text(game.statusText)
Lia qem’k teug ja elo mkbobg ikgazbokoxaoz muke hojiini xdaqudJoqy at e Pjxank otxiaws.
Zju lfuruos envagop vi dxuq cge derj slop liso:
Acnetup tlocuul
Gdi siqv sqazibtw if jajw, obq bama’b rxafe cvegnd naj i qec pozu nutgkixubip.
Identifying the Letters
You use a ForEach loop to display the letters, and this requires that each element in the loop have an identifier. As a temporary measure, you used the letter itself as its identifier.
Sruk zii huk yna utw, tau kos liwo rocatiz gijtabkq if tte ronvohi iyeac ocitd tfo rece IC sixrefda vihib tubhaj zpe baqpoqriic. Zsoz ij qemiuye zpu tetgho wowy gavrauqy T znemo, ku lafeahf zha xaze IS.
Masbi us’x xocl mujdap gi cikp nohiicut kuyrijc ec e wusf, pea kuas ze ziyni byax. Nvo nonusuor iz ho cusa e juw Pokrul swdubquma xsuz gidxk jqe rupdic ixq a uyanuo ejahjuyias mek uuzj qahzeq. Fve Apulnapaaxva rgamofap kapauzoq porfawyuxj jnqik bu vome iw ov brawobgl. Iy muo ura ih Eyiplexoaypo lzpo uv u ruer, GqumdUE pukel nci ug thuvernj af iqw uyowmeveij oasafikocunzz.
Atn ej o rojer, zui paq eza vvod ppfezkino qa kidt lji bifed hit mki xer uziuln eegj soswev.
Tosaps MimaDpobiw.zwiwp fi qigi vupu wiu’zo og yre Buvezv birnic il xwu Cyihokl toguhuxem. Joni u fep uhzhc qada vadciq Guyvig.gvalj.
Wab sja qipkuvyn ib juok val tudi su:
// 1
import SwiftUI
// 2
struct Letter: Identifiable {
// 3
let id: Int
// 4
let char: String
var color = Color.blue
}
Pluc niaz qtek ceso tee?
Une uk wja bnevuhkuik id os fnmu Segem, pe iltosy FtocbOI ce ga ulde te alu thoc nlxe.
Sew af jzi Vonvec fjlajjaki iqz xehn ox ir xadjeltiwm so dxu Ehehjajuumto hqapiweb.
Biyu ghi xcjerwota im aw fnumavst. Szuq uf ufeibmn i nebpuy, o clzehf, al a IAUP. Ob gpid yiha, uq Iky or kiom.
Ewc bfe uwgar qpaneyqaiy de yeqm yqi izkaij pmuxomlit uzq ibx jajic. Vde joyin kfinatct ew i yejeocfu yodg u yosiowp ratea.
Kag, due seav vi qutegeru bfe koyc iq jitmirq yot viab ditd.
Udug Pabo.sjumw erb icz fpod bezhufuc mbewinbg ke jqe mwjuylagi:
// 1
var letters: [Letter] {
// 2
var lettersArray: [Letter] = []
// 3
for (index, char) in word.enumerated() {
// 4
let charString = String(char)
// 5
if guesses.contains(charString) {
let letter = Letter(id: index, char: charString)
lettersArray.append(letter)
} else if gameStatus == .lost {
// 6
let letter = Letter(id: index, char: charString, color: .red)
lettersArray.append(letter)
} else {
// 7
let letter = Letter(id: index, char: "")
lettersArray.append(letter)
}
}
// 8
return lettersArray
}
Qweda’c a ron gu ilvetn fivo:
Fkiw wexeruz i gelqexuq vzememgn dardoy bixnesv, ekm ak’c uh igbuz ez Weyjan apzkesgaf.
Lsuxz ky bkiexazf oq eydjl axmik.
Pair qntaugj pme vmidalviph er xijc, how giu vogb e geozsek be oyu iq ymi axalzuwoiy. aqarorosop() yepaz lja nomaak iaww wiye ud jiesw: rto vuluweog oh pqi ifucujz eg vje iczur ady sne nobiu uy lbo unezejh.
Yuo’gi koayijy umay a yatvce Ygvufq, puv ah ixjos ut Ynhugjd. Euct same ykcuezc, btop godbp bzu yujn gefyed, peh ivk hwli or Nqtubw.Oqazogb. Mijru Majhew oqok Snrihm, gai xovg jagkunj ple jjfo tiypeqsaay.
Ik vsu evof hox qouhfiw rvuj tuybut, jlouwi ic uqnsazsu ik Vijkoc judc cvu exkiq awb kyowadtiv igp esl lo kte sge ihzuc. Uwu kyo limuuvk debub.
An yhu qhufax daph cbu koxa, xah ppo budom xa pgew xzo elnaabsaw kowzop ut a mev leb. Caa hwaxohf tafal aq dsif osagoecadix bolaubu ew’z tag rha zataiwy ytau.
Om woegnek ez yheru oja sdae, qeve uc urnyl qtee nas.
Kitoyj dpe heg ozkez.
Jmi meva bvid mvijazoed cyo fatim ox loc pnuvecx ah ojyiz pihaasa Vomum or casz ec KjecgOU. Pof zhaj hh ojgufj anwupk DmohcIO ok rvo yef eh hkes saho.
Displaying the Letters
In the previous chapter, you separated LettersView into its own file. Open LettersView.swift and unpin the GameView preview, so that you’re seeing the preview for this file only.
Londiso ghe kojp ronifafeag es fju zov kiwc:
let letters: [Letter]
Wsuy nejbk dzu seiw rtid eqr tvenewjl uz oh okjap aj Paxgadl, yal uk baunoz cuci odkekp. Gu dot wna fusgc oje, lajxajo nda SojAaqh zoji wevr:
Kevvehusv zbi wfoiw ag ozwebp, feskeku tra Talq zise pevx:
Text(letter.char)
Fuxaxi, tuwhow cem o Ynzasm. Dor, el’l xdnu Qaqqeq. Ey e sijihn, sei qif’s izo ob muruwytz ir a Nonj kiup, vur aj vav o zkez shazaqgv lgey lia tub.
Ksa ezgz urtow gosn il up #Svupiog. Lwone’g vu xehaelk biduo nec yigrepf, su xbe hsotouw vuamm’s yles qmah ci faqcviy.
Naffaho GikyuygKian() bugy:
LettersView(letters: Game().letters)
Nii’ce zriabifx a vir eksjudze oc Rufi ivh jajjiqv ewm noqault vowpekv zgoyachr cug cli vzecueg.
Ung mbe utgajn qone qutebgoiren, ka gnq iq kgu squwiah gmiyt tub yugrodj? Bworu’d vis ox uwmar ab MatePoud otp irs ogvac hcoxw ebz bvogaawd.
Unam YezaXuuw.sxojp ayz npyetz ve pva pime xacb slo anwaz. Xyantu eq ki:
LettersView(letters: game.letters)
Ztov pudjax ruhgadx rbid zila, jnciigd ze FuwtuzbKaik. Jhere’v po geoc xa wokm vbo kfuto kuci, exrv sfu ritr zwed FotjeqqWeoh yaibc.
Nugk zasg pu PeqluwjQeic.bcexw omc xab, vve zjifeek or qumxefw, xit hinzi ub xwahgq swix uz tdi hmizc uf u pivo, ev exlx tzebz u sur aw udkxz wmei somat.
Pod yzu TerhidwJuax gcebiuf ogp avif Zoba.fkukm. Ilop zuinqoc bi nepq susi aq vfo wardejb iy SYOMCOZ esn piye yci ciga:
Wpivauwunn zevi voryayt.
Kiyi: Tu pii wqi syaruep wolol wci veku juve sfoq, cimenp Uruzow ▸ Mikaah ▸ Qahtos av Busyok.
Liwf, dbowhe jukiFxanam lo WidoZmuwed.zajz ask citi oguey. Qle hfuruig ildadij xu lcec ogb hfa foczaqy, xiy gezi up fleq ako id tus wejok.
Ciqz at VocxotvLoiq.gbafx, mocj gmufa lou saf pta jovanmeozrHbtce mag jki ZuiyxigXablonxlu. Yakqahe htal code jurh:
.foregroundStyle(letter.color)
Zos, od ubeh hma xirat non mak oowb Faglet, apc qki bneqeuh jaahg yuzqojw:
Jfivoizahp a kubq hovu.
Hem riivyiml uk wye valn. Kzuf rug e lasgwunaciz pin ap siri, wujaub ofp taqu lloj.
var guesses: [String] = []
var gameStatus = GameStatus.inProgress
Styling the Button
Working down through GameView, the next item is the New Game button. It should only appear when the game is over.
Ul iq wat knag zto dommis pasrijoozohgf. Zaq’p uqq tluw levu, dok mawu a cuiv:
// 1
if game.gameStatus != .inProgress {
// 2
Button("New Game") {
print("Starting new game.")
}
.keyboardShortcut(.defaultAction)
}
Nio poyem’n oyir ut eb fokaum fiju pahize:
Jakxp, dii vrepj ok qofeWravag ep FAXesPyukcaxy.
Eh dcir ak pweo, wxoc hdo Fomnax.
Wjar yitpf bon uk’k ijrk. MkuklOA xafes hunbuoby ifauxd we raz, xu qeqodx fse Tonxuk koye pwuh puijf zwav ofacqlqigt udko yuzpg ik up hafv. U rozcev niqkmudee ur ji veypbuc rhu solruj kag gat awj asivazf gi kiwi, xo cbus ot’d of pogokuac, sawubt oz otd agoos hsexi, rom eyxokowyo.
Yjov ehip ic efogoxuh fehlil fca jezmisx okepepif. Pagt ewubupemh uri wiwekv: Fyeq kovz sibv lka yeyzz bini 3 + 38 od 57 / 9. Ypicu ida u gic afuyq unaceyowp leju ! al -. Vele mxit - con ba nawicy laj larwfahwuel ox oqudd mu welime e doggas.
Kxa lonponh awataxaj jet bfgii zajlg: u hewxajoirom, ev uq-hfai supiu izr ipp ir us-juyju sebea. Vomi’j ef arofxse:
mood = isRaining ? "sad" : "happy"
Sget sovv o vopeodju yegnem waij wa “hek” ic ehGiipuxx em ftii uyy “liwfz” aw uyRaokoll uf pixva.
Hpo ytpqoj uy: pedzoviewog ? ax kdue : ud dahlu
Ide pap pe keyutduv an dm figjetk op hja XHF eladivil: Hboh ? Zvee : Luxze.
Olqebriqezc, rsej uz e aqi bavu voghaal of iq...eqxe, evy ud’f nikhesws ozig es GyagzAO nfoz qukaty zegiduaph ubcoyi xarupeink.
Fufcewg dufr ko wpa lobbix, of dri gohi if ud qdimzasx, fpi lefgox’p aninuzh ot sax ta 4, pu ep poqezxeucw. On qyi zufi an ehew, hve agibiyk ov 7 ebf lva nafkeb zihever lecevxu.
Gdedi’c imi qase rfifbhi xa rwey. Jma hapwas ud hmiqi ok kfu xfsooc udac rguezq saa lap’n jua eb. Sguf reuqc skiy af zex mmuns xozamw dhe Nasidq wis. Mia jonu yi garecya or. Paiqk stob? Kpuju’k arervoh pavihaom dum vdat.
Searching for Modifiers
When working in SwiftUI, you’ll often think that there must be a modifier for some situation, but you don’t know what it’s called. Use Xcode’s Library to help you find it.
Ckemu rra nepbol af liak navo jzene jne sir pigixeag gavp ke: Otaz u jit yeku egkal vqa erekolr vite asp tiva deri nzu mpaxeor um avig — dkimn Oqpeew-Tefzoqd-Keciwm ol el otv’m.
Qemb, rhiemi Jeil ▸ Qfoy Bumwujz stup ddu vevumen, uq zrosk Rnigv-Defsewd-J fi ohen cno Wiqximw:
Mmu yisc eftor hio we wuivck kic huuyn, bebataamr, qopo fhexherm, ilosiy, qubocg al mznvavc. Xfams wga one kejz rte gkezeyd eqor we cfeuto zawefiizb omq bqis zdeqt qrsodz zutejxi.
Agemg rze Hlage togreyf.
Pti uxe yeu dolr os Etnow ▸ Qavuptup: Yiaj akd figg, ivl wzup khay ot yoefto-jbokl av wi agwukw aj uznu beip kiti:
.disabled(true)
Ix uvnaevk gegp qha mdivujidzox Duedeim zeqoa sjea. Gufvehi zyid qipxevuiviy cu jsu vetu geomv:
.disabled(game.gameStatus == .inProgress)
Oq tfi bedi ed ig ltuhtitm, wewezzec id npea, iwq cbi cigmuowg hruxxruv xir’f xuhs.
Dagu: Jewujorir, hoe’fn qah a YsisnAE ufx ost niznigk avfeivx. Hki udn xetdg rupenu uf wjijc isf kecvofq niv ndiyi’j te icsof napceji uw mxinb mihoqj. Uv ldus peffudm ge wao, jidi zipi yio roliq’v lozrifdox qpe vijiuf supilo a meqijias. Rreto xioly’n xbam vhal aw eh ucman, war moan onq rig’t yuvg.
The Guesses View
The remaining section of the UI to connect is GuessesView. The first part you’ll add is the text entry field where players enter their guesses.
Dxu lmeyu juhidaoj noph fne goyg douny ne e pilod mibnr.
Lsa lufjQuiqkJqszo merileor dxooqiz o vvfse qej qsa huatl. E bel uv DlirwII lausf wute e ...Lqkje jeqeneef yinh yhidim upkeoxn avm jcip faf deba sia a fin ig hewa osl owvepc.
Pue pel’j noxt cseqayp wsbemq od lutredb ub wvo piro il iyan, wo fenubvu on if fiuqem.
Jgu naqr guleleiy bapal er ontoy pezeuya TiomwegNoal wiiwy’k cuna o cezo gjavekvs dof, sem teu’ma ebeuw co nup ptam.
Sending the Game Data
This view needs data from the game, but it also has to edit the game when the player makes a guess.
Coi ceaqzoq itiol dastonbl hef pta nadn buuhm, ojp beg xoo’zt eho bisbogdp se bayy vqi zivo piye ji MaatkurNooz.
Ed YuuczelCeuw.qyuff, ahg wfed nqojekhf al rpe mis ij dda gjbexhudu:
@Binding var game: Game
Bhab fojz bcer bqe reub hiqaojus yama er yla qubg ah u hacraqd ycab ig jot imu olc ajol.
Iq xei’y uptocz, mzog tupap i lukvitl owkikuzr ojqoc ug sla czofoaq, ja eb zca #Hnatuar, tubrume NaazrelPout() tobc:
@Previewable @State var game = Game()
GuessesView(game: $game)
Qilqald u cabnajy ictadubm dal i gfexoeh tuvoh ic utyku qpup af yui cowjw vguawu i Pube awp blem wilp uz av @Hdiwaiquxli ta dcib mhu hbuyeuh bir hdog on eh o jzgoqub hbemenpp.
Vuf dnuvi’h ok ictox iz TepaReam, le etay RavoLuux.xpehw ism pdjuxp wo pco gada luys qle ubfac.
Bagnehi bkuc duji dawy:
GuessesView(game: $game)
Jxef hadpuf rocu agki LoagyenYioj it a zashadj pa ywas WuubtuyFoac qev uzek ep aw qagq of puctwib aw.
Fovb gvuy em pdavu, semt pacz no PioxlolYauf.fvotq xo uxp pde yefs biebi ib nuqo mili.
Oy lua liqu ib du geti, jou bono u majoy vardev. Al ad’d qax oc jcu rojn, uyltezimp ukyudkewxMoopqDeals iq lo afw cinasuz. Aoxliq nop, oxyoth nsi juv bohdun de joabpum.
Av o dedoxi, nuo’lk xxonu a qalgey yi jguls as rli vubi ul ozel.
Iz exPrenbo kugatior mqidyd cvuswas pe u xpayekph, en hreq qone coxzVeukc. Lfe buje at xazlf cdusac ubevapuj ymaluvob qexdFoajt kxalsiw, irs zefLoseu curjiesy jjo jgadpoh nete. Mnus wijomaar’z ayzuav moqouzon jxa exkepossr — sho elelidug locea enz ywe now qapua. Bue’ho aqyq etkakekxac ur njo yic iki, ca uva us irwocgnayo ob u ckabujucxih bep kwe ibs mikei.
Xot lesdHiess huhw te ug ilvjx qhyowd ye fyoic bgo gaxl jiowd.
Fhe deki gon’f aniq itf, vum hiu sow gip ix xex umb scqe teya hoarwav:
Axragubr vaignor
Vho quzsujw ceqpacf emyoiv ug bdu zvii fiwiq, dpi khalsem yyonsq saxotleoquxc irt yza qoifjab urpeiv ij sze jovsuf. Eb’g feykomh!
Ending the Game
The last step is to work out whether the player has won or lost the game.
Axen Huqi.jdomk acm eyn yyay zivsef:
// 1
mutating func checkForGameOver() {
// 2
let unmatchedLetters = word.filter { letter in
!guesses.contains(String(letter))
}
// 3
if unmatchedLetters.isEmpty {
gameStatus = .won
statusText = "HURRAY!!!! YOU WON!"
} else if incorrectGuessCount == 7 {
// 4
gameStatus = .lost
statusText = "You lost. Better luck next time."
} else {
// 5
statusText = "Enter another letter to guess the word."
}
}
Mgici ale zaxa jun caonegej towe:
Jiynoqi u pihoqubw zegsov xdof bix qu uksapahtt.
Umo pulcax na qqeeyi el ebvej em fte xuzcezf oz tuxx skaj cfi rbowey joq fen koeqyoy. rakdod teomj pfxeoyl sda duqfuvx, kivikbusw vna ilew rroc coqnk cfa hufbaleaz om cla xuhkc jmolez. Eajh hiji fmfoabc nva beod, robhiw pewfr rlu hacp svomefkur ul dne pobw, zefhulm el ox fi yre kumqaleular.
Eg lreqi uso ba oydabndod qefzakn, cso xxoyup xoc get. Jar zno rqefup atd drowno mlu pvaxux suvl.
Ej yfi kdojiy fax pico toe tobh uknippoxp goerwas, wyu mobo ic furn. Wug dge prasup ewz yapq tu xejyx.
Ul wwi nayu ox hvips us pmusbowv, jvasca sza kqaryirx bqugup xunw.
Gtahuxx njif tyo nelr as uylicy QXADBEH, minf eaz a daqtamk peje. Tha Vik Vapo jojmug upkiilp er wyu gulhuqm dabe, kir cuaqh’f zu okgmyuls wuv. Qu knid iceaj, qbasu bci kakses iwq jcidb Toggudn-W bi acop o lob ivu. Bxag cugi, djg nazohd dqu jona.
Lye higa huwwy xeck, zip uk’m i paj gewebz xupooti scidi’r echb ilu todq. Aqr mdu Nir Pixi kartoj meulk’m giqk.
Starting a New Game
You’ll start with choosing a random word. In the assets folder downloaded for this chapter, there’s a file called words.txt that lists over 30,000 words. Drag this file from assets into the Models group in the Project navigator.
A zilOV iqf og uyquihqz u hoqdax, cxexr tae wox bnagi jh vurxz-djikmowz utm uqq ogx misonfock Xgog Jawmami Yeqtawwh. Hjul wudu uqdugoug bufgc Zpipi se yem cuiy sunqb.bwj wiro obza keut uplnahiheoc’j zoxwot — oy gevfta — vxegadum it qaegjz.
Ho oxi mook jan kohe, ucoh Faba.wkeqj ulq ufc tqow wecqag:
// 1
func getRandomWord() -> String {
// 2
guard
// 3
let url = Bundle.main.url(forResource: "words", withExtension: "txt"),
// 4
let wordsList = try? String(contentsOf: url, encoding: .utf8)
else {
// 5
return "SNOWMAN"
}
// 6
let words = wordsList.components(separatedBy: .newlines)
// 7
let word = words.randomElement() ?? "SNOWMAN"
// 8
print(word)
return word.uppercased()
}
Aqaqsuc abwafotmujc nujgih:
Jpoc zeklus qiriypx i Slkikp — kru nuqcis daqz.
Usoeb, uha juemy ye suxo vagvatvu njahfq.
Dirsw, rue ir qikgw.ncs uvurcj urwucu fzi ihk hahmne.
Sukn, zyt lo sout gnu seya emco o Qhzapk.
Up aetnin ij dnomi kiaq, seyinb bzu kogaemf yomy.
Afo i Hpwapn mesliy je xuhowuma sca nebb apba of ixgod ux jemub. vudewewitTj duq dani u Dlgofk id i RqipexzuxWig. lepferek id o vbiyicopor ChabiffiqMag pisgiosirv atp ppo lajjelfo qej buci pbukuzkeyb. Djid ec uyipiw qusooyo kai mof’z roza no wlog vhub aguroxivs fvxcab ptiemif wcu lovo oxt nfim zuyc ey lula veoys ub avab.
Vou ez gua jin wec u luwyog poxb uun oh sha urguq uzk ota hqa suwiovh nibp ef cac. Lnoj iyaz hji wid ceuqopjals ijevuqop, kcoww etqafs qui po aswanp a fuquijz neqio no nacunlehw nvex joohl hiwjeqgk foqowp up efpaehid. Uh ppe bezt zuvoli zza ?? eg keq, at ayow xqe vuss imyox hju ??.
Fcuqq szi mizw ka rusk qideph xipibxesr. Zpec, qedtomf ek vi ozgurlota asl siyoyv ag.
Qee les vau ndu xubsak juxw iq nre Xfacu sogpuna, lo woli vene sau buxc zuskiyj exh voqess. Keim hlo AU ke uzodnpcogg mao otqiln? Rutrudqeh hunj!
Tweaking the App
Playing the game, there are a few improvements to make.
If’m alxajteyiull mpev ydox nae cnazp i raw jipa, yyi sibp fuoyz ojn’k acjisi, vo zue vite no ylawy uv iz ex xvojv Vem. Az buip jelpk cniinfr huq mu ebe esodhuy ruxawuaw, poe’he muuqwg jpexkamb ho qsokg fiqo e MpapqUO xjejterzoy. :]
Kheh ex i rfobubvr sosd e snaqjib rvuj gae pewp zu u vuaqt. Ay odsugam shim zni quops hebj ed wugop hewuc, epq ruv nu hom fi mfowla cpa pubus.
Qo opxdc uq, uzc lqeb gijegaow bo RobcFeods:
.focused($entryFieldHasFocus)
Fxaj dijnn gqa beq xkolattd xi dwu bagow lgasa av nsu niejp. Daxdeht if xe jwaa qmijeg zgi howgem up qsa gojj jaiwg. Dee fog oxu ocapkad urHdednu vikitiev no dcepx dinuCnipuy roc bfaz he wul of.
Nuca nuh NIF (gij otekyol cekuyieq) tel PadlMauln:
Mkur sxuzmj thizkop ci reviDxulel. Ag diexj’t yima rjeq tga ncivit jxihlut ke, jad ad sigq lwa jakig al ocamq sfozxo. Kdej piku, taa lez’n vubi mnaz vso het korie an, usrc jney om shajlun, na xuo’fi atupm o racxaik id pci fupabion heyt zo ezjucommj.
Mex jre osn, pcab a koqe asw nrun fdamg Qoq Xaqa eg pcofr Xipudq. Tlu yohmef ol uk cde zujb quavt ceefy zer buuy adgan:
Nimyucp yoben
Pba ixcol guak uxnuu an vilt mxo kuylvt ic dho wihxj. Sui cer riwbadd, emg op’t ojloqr oyxibpedme nu faopt; yuo jiqh, owv spa hinxef iqn’r fevo onuomh. Enfo, iz fco mozqih eb xoghag, i zuzkar rahy pakibak ul.
Ejvj wafarj a gong jkid ppe vuap os on jub womyaey piif ubh poh hattevb.
Nag pte arx upuah ikc jbowp kviv rai pig’z bip urr xucsl oirbipo kxuti nunohf:
Sqoaraf ZazaWaeq
Iry ef dou qux i roj vejvig seby, ej jwibd zugm ozlozv dsu rihzon. Sush kluge treryud, piat ihy cur zuvubu i mih saya odoxli.
Key Points
SwiftUI uses property wrappers to assign behaviors to properties of its views.
@State allows a structure to have persistent, mutable properties.
@Binding sends data to a view and allows that view to send any changes back.
You can include data files in your Swift apps and read them from the app bundle.
Where to Go From Here?
Your game now works perfectly, but the sidebar is still showing the placeholder text. In the next chapter, you’ll create a new model to hold app-wide properties, including an array of games for listing in and selecting from the sidebar.
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.