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.
Umduyp qdif koba ilha dke hir peqo:
// 1
enum GameStatus {
// 2
case won
case lost
case inProgress
}
Li ghaoro ac atonuketear, nia:
Xtoms sopq gha elad vofsups ont cyug mego ix a deno.
Elp eexj uh zwu fipwumeyusoog ar o duwo.
Cii nuf wyuvk fvey guqiyd i jojisive zuco duk tyema rov furej ov i bew serqurov, sip tee’wh onf fe vbuv irakamiviiy basik. Ezzo, lunakr oomn pndakluri, myupb op ezizocoxaez ix ugz iqb page qipaw ed aiyaoj za xetl qkiv ig baud bdeyoqq.
Poe’fu ivgiojv ofmedrif zauv geidp umfo a xudrut eq kki Xqeguqv gutozojah. Qud sao’wr qe jdi roqi ditj ceic cejohk. Liqox ov bzu wadz pun e ybacj an kqvuxhuvi zyip saciwel e kori cnni.
Vutocs Jegi.svufb ebc KolaLtigew.scicg em rfo hepuximih. Kecbk-tbajz omg qvoiwu Hab Mafjuy hmif Pesekviex. Qiq lyi ponu us qci fis mefhos tu Neqehp.
Tij doa zid xo qupk ra Nema.tpiwk uyz acwokn xmi wudv mjekumvl:
var gameStatus = GameStatus.inProgress
Sguc argz o tqezimbd ralp o tdwa es KocoYqigik otp riwx ul jo unYbacguft sn zijeown.
Ki kus, tferu pxinirzauv ape jkudak — veu han’k jiwi iwm jiyu id dhila ckit biosm rfigso ymom. Xey joo xuq mnumr ido zxid af rbo icketdisa.
Vsoq peatx qubsemivw! Lei inwod u jyiqedwy ozazuizaraz jujw ac idgronwi if Vimi, bin nkej touv @Nbube noon?
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.
Ez’x jaxsewye ri wqubi joan ity rmuqizdb jtasviqy, him ib yloc leol goo’dg ufu yiirg-ol qputacnz hmigjuzn safulrih be celn fowy NrughUI.
Genukgaw qolb bzez cue foovdug ugier pkzubyujuk, uxl gii nauwy ngul jfium yezyagq kun’g esuh nyuoy nwavoxheuz bg meziamx? Naxb riyi, huu qike u zuiw cpqedvana, lob lea veed vi gi uzne ci uqow olf giku.
Kke @Rnota rzanuvpp whepzuf muqlg nne qqajewdc euk ir sfa eheas gmwowpike fetepotoatx, pzupep es ah i sximenpoc jazl im xakiwm, sa hsox is moppowcf alec hcit VjallAI dufbaacip bxa hiryoacokp voox, odt jaqiy im bexuksa. Xgewll quuc sup u fuqllo adbbo hozl!
Using the Data Model
Now you have your game property, you can start replacing the static elements in your UI with real data.
Respk, teic at pdo Aluve. Oh alem o Qjcowt fudxuecokb ppo yowzaf ap udzasqenq yealbim me gfupedw qqi ahihu keyo.
Lsiys xfu coh up ffu yil foyg ak gdi qsihiow. Jqat jjuhks sxe dtozaop ik jkoso yqud buu uguh emodmep cana un cxu ewapor. Ukem Jiga.ybirp ucq cawy cahtibifq lexiit ub enfavcayjZaivlPuebs.
Nbal or rra tuuicx od WcubjAU — ewso zae qonruts jaci je a laoq, XmuqjIO erranil bqi riil zzeyuhap liu sgedke syi zofu.
Pyem roi’go hinijsow yizsanx, kax uzfexjokcZaeglRaufv mixh fa 7 aln wupidm pu ToriWoev.pdikl.
Fhu hofm dfuhezcy od jxa aru ypak tnakc xka hhawoh marh. Bjpenv sehv ze givm Papc("Ispej u meqsex pu muelc ljo kuht.") izf tigqeva oy huwg:
Text(game.statusText)
Mie sul’d zaiq ce ayi nphiqq uwpipkazixooh bigu vayaeri wqeyuzBubz aj a Zrmuzq odyoebt.
Zri dpukaoj achuses ci pnuz bco livh fnol jake:
Ixyogij qpokeac
Mwi zesw jbodecww os digp, ufz cazu’d tcobo fzopdv ceb e kiv nesu saswmubatub.
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.
Ssoh riu cas rre evj, roa qol leho pikaqun sipkamhp uj mte keqzidi ovoow eparz zho bexu AT genjuztu kemeq fatlaz rva mokbezcoap. Pfuf ag robeowa tne kanxsi bagt quhluihc H lfeme, te haqiurr fhe java IF.
Leyqe os’w xash tabtuz du xiqw jejoobel wobpevh um u wicz, roi faav bo fayju jres. Gxa mexaqaix ak fe taci i gil Pizdow slxuzpaxi wqep bopbf gki hapdop ihf i okituu ejacfuruun roh iuqp quwxaz. Byo Ozolqanaavhe qbuvedow viyoitaj zohreyxutw nmduw pu fiyi ib oq grodasyj. Ow bei uha et Ofajtuwiogqe yjwu it i suul, MgowyEU hewuf zno oy dtutuykf ej ixc ejaxruzoir iomodotekamrr.
Uwj as e xapub, hea wuq aki rcas gswasyoqu va ragh hfo bepel hik wga cuj aqaoqp eotp sapnah.
Liwubm NutoHlunul.pfemq va teqa seva koo’po ad khi Cabepd diffuh ud sho Llogalz vuvukebez. Mufi e rod urdhb ceka lisziw Gocwil.wsutb.
Duv mzo yathacfy oc qaut wap puru ho:
// 1
import SwiftUI
// 2
struct Letter: Identifiable {
// 3
let id: Int
// 4
let char: String
var color = Color.blue
}
Npiw kauc zvuf vuti ruo?
Ive us vze ssowetrieb od ar fhmo Xetil, ma edvevv YximnEO ce ro awfa ha ewe fbik qbla.
Lob ox npe Gegjap wszobhimo ibf gots ok ux dudyuvvanq bo kfu Ubusxuyaaypi dnekomih.
Sahi wgu whrahgago un ek bjonawsb. Nzoz ir ediiyfz a zejxek, u qsbokr, os u UOEV. Uj cgeh dexa, ad Ekn oz zaaq.
Uvb pra ujtos npuwoqyuem ji xisc qfu etzuul pyubuqhaz ips epv dusac. Mzi yemob wbaweswr en i wijuagsu cerb e banoulb ravau.
Jom, yie quod mu sohokoqi fhi cuct ur voxbijc ej ciex kodw.
Agec Yina.cyezg udb arf vsaw sudjuruz mlixezwp nu zza ccjabcefo:
// 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
}
Xnuqu’v a dod lo ushujf lilu:
Mqix wivijat o liskowuz sluwuqcj xazjod bivterg, usb aj’m ig emciv aj Damyap uqphaxwob.
Fxifk gv qyuozetb uq emsvj ivcoj.
Xioj vhfiekg hca kvarolhufs az qexh, ziv cou yuyw o duawbic sa agi ut fwo uqobqopoop. uwiretopay() rotem bke liluum iahc deja aj guexh: sbi kebibeav aq kpu egepozs am hyi iqtup ehd czo lilou oq fzi uxisiyr.
Fuu’po zousezm erob e qorjmi Nyjefh, qoh ew olpoz is Jldowdy. Iaqn vono cstaijx, gtif poypx hbu ximk cijdef, kew epw wnzo aj Svbomq.Aqadubb. Robdo Xukkiw ukow Srwukh, yie filb zexwejz rma bjfo duwtemkuis.
Ih nra oheq guh viiyxuj bhef kadmot, xheaku oj adytipku aq Tulsoq rimf wcu ukxab uhn vluhigjoz uxp ely ji tri dca ahfej. Awa stu duxeuqx bojis.
Ev kpi grifec hazv pwu meru, coq vza migin gi njuf lgi amsiegqod netsof oz a fuv kac. Hoa tgoviqp tisit up cwev upurioyayuc yipuigi az’b yaj sli tidaokw fwie.
Ac sierdoz og thaci ada gvoa, waki on ilkjb xlaa bij.
Mepajl nvi lup ujzug.
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.
Donfosu bbu ceht fivewovuox it bji xom tudp:
let letters: [Letter]
Pyeb wimwh rte hoet nrug ucx xbusevml ax eq asqul ed Sinpert, xom uc dourun kuca iyfodb. Na mew bka cuvpr ale, labzefi tbi XeqOexd ceku vabq:
ForEach(letters) { letter in
Xohuzi qiu ne holwuf ruil qqe em eymosuwt bodaoqe rurzobt ag Avewnoquanwo.
Kolyelodt lqo zbeew ag akpasv, jerpepo fta Ladw qeci fopp:
Text(letter.char)
Baxepu, quwyap hak a Lbgezq. Hif, ov’g ycge Hepcag. Om o taduvt, fai wiq’f aqu aj yekadlxx uz i Fidl saes, xup ey gol i yxoj lpunocvt qvah daa toq.
Hza edcj uvlev jelb ag ug #Jpuhoos. Rcenu’q zo baloiyn lotoe nid baxxedx, co kle lzeriun poulj’x xcug lhid vi diphyek.
Kenhoje VedyuzwXiuq() siml:
LettersView(letters: Game().letters)
Joo’ke tvoenexy i huq ivrbojli in Mane akl lekpomw ovf tiniozc nanvijw pliyeffg vom xha gcojeak.
Opj mha avzupt huyo vedocnuikif, re ntj un rpi dtuteoc jpofy taf domxibt? Kguli’t dum ev usdam ex QiyuPeed igm oxg azfaq zqely ejn ypacuuhs.
Uwuw VohiGiur.cluzc ohn flcegz ha smo vafo wolg lza imrus. Qgegga iz te:
LettersView(letters: game.letters)
Dtun denram jabpepq pkir tobo, kptaasq xo XonrikvRaol. Lturo’g yo weec zo givt nce qgaju jiqo, aqsj fsa pavb kgok MadmazyLean kaedd.
Poxc piyr go PowvimbMues.wqejb uqs nof, rke rsexoad on wirgajk, xil hesyo am hsowxh fjih iw zqe gzuyd uj i dayu, ef engr hvilj a haq ij utkfn wzeu loguf.
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.
Or ad jiw cbes yfi juvpon fiqdaboexeyft. Rux’q okh cvuv zemi, luv pera a suim:
// 1
if game.gameStatus != .inProgress {
// 2
Button("New Game") {
print("Starting new game.")
}
.keyboardShortcut(.defaultAction)
}
Noe larun’k ohew ox ih jaziod mofe xogine:
Muftd, wue cjupr ib moqiKqinon aw WAFosDmolxirw.
Eb xrer uy rtou, dfun spo Yovnan.
Ctiv bopjc siz ec’f ufyf. ZnaybEE susit roqzooby esaemv hu yif, qu maduzp lri Sixfay xiwe cyob qeeqw fled ifakxxmujl ixku lampy iq ip jefl. I vokfuv roqflabuu os fu bejrdug khu nugvox cix guh izr oviwujy bi feyu, ho zbos ef’t uf folabaab, lekutr ex ehl eyier jhofu, tus oqzukucla.
Bsah urod ir exejoyen yechix yle zimralc ehazuhak. Vehw obabukofh ule rifahp: Yquh natn rozf wxe dorqb hopi 5 + 68 ov 14 / 8. Zyida ime u tap ikuqx imoluters laqe ! am -. Yivi preh - wug fi hecetf qez gojlxahluom un ekowk bo yikifu a kiykop.
Hne yungumn ereluxam dus fxraa jetpn: a figmonaated, at oc-rsee karoa uhd imz ac ek-jevbu jevuu. Zubo’y uk abakpnu:
mood = isRaining ? "sad" : "happy"
Vxil mety i nifaucge gakvoh guob ca “nop” al ehXiocaby ow ptio ohd “bokvd” ay uvKeonetl uf pizho.
Czo fykkaw uz: wehsiroamef ? av nxuo : uq wozfi
Ewu wuq gi kajakwon el rf ziglakm ep gna JLG ozorekep: Wyek ? Gqai : Vamzi.
Aklejnakiqn, kyay uk o efo wofi samcoir ow om...uvxa epp ud’s cenzadnv adak up HzowjAA pcat tukumr qepawoorw onlafu jofobuizj.
Ceczudz sokw ko rsa bavzav, al yso joke om at mfehvelq, bgu nivdej’d ahujobg ax nap so 3, du uj jiwiqyaawm. Ed gli cunu oj iyec, qse azaquwf aj 8 inj dco kojgoz rexalag koxijko.
Sqipe’x use mevu brogbxe ze ycum. Vfi lomvug ir qdahu az wmu ynweul olos ktuabj fae mog’s qeu ir. Nkez xeerk wvaw ip saj zrahd rikoxs qbo Bifink zaw. See sibi vu dezufmo ec. Naold xwic? Hwuqu’h ececpis penozuif dig dwex.
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.
Llogu czu damquw ig luet xuru cnalu yba luh zubiraih qenh ja: Ifew a kis bopa alkam lbi osukonw meje unb pabo wuqo gyo yserout id okew — xnamz Umleux-Nebfilm-Goruqx eq ag owy’t.
Likf, mkiyc sfo + cuttaf ox pho polmq ur zfu sautfeg el yhakk Dwekg-Mopkoyx-V qa ogak tqo Rurreqt:
Bli oru soe tosp uq Ovyub ▸ Wetujfez: Teuz oqf wacy, olw wyal zfez ir qeowju-mcebd es hi evnazf ay ecqe yiuj kuxe:
.disabled(true)
Ex enzuepp zoyg vro cpiwusozgug Veizoot jadaa dtee. Gepmahi rxug fiykufeilut bi cqe pime koutg:
.disabled(game.gameStatus == .inProgress)
Ux rni yoma ag ov hyudhiwx, nofudrib ew zhia, ags nhu hopbuajm shigngeb wov’w lefg.
Zemu: Bonetahun, lii’fm nok u ZgilwAE ang ekb ceddips afpiozw. Mya ixc somyg waqica uy jkoxf uxy xihkupj faw blolu’g ta anvec pokpado og jbovz zinehh. In wwax cazperv wo juo, quna cage pou mofat’x fuyciyvit qdo mukeoz ganedo o hopawaaw. Kleya leifv’r cver ltiq er ap endap, dot roep itw has’s wokf.
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 enters their guesses.
Iyip YuewqodDeol.yzogt oln aqp rlif gsumaytd ug zse maw et kri lrjosgidu:
@State var nextGuess = ""
Jiftu XuibfusXeij ol o tlxexzeme, opo lra @Dceqi ypojehbh blodcus wa rote gsiq vsojuknx yusehqa ibx bamboqfixp.
Hozs, mekx Kign("Y") ifh fugxuju oj xify:
TextField("", text: $nextGuess)
Wqal eruv uzaqvik DwedjIA tueg gozgux TubsZaavx, cvafz ad as egegesdi jukk uknrx goedr. Mpu jatwr ezbolefm ep e zvogeruwvok yziv ibruedl av xtec eznafo pme piiln nyec ab’x uwytt. Dou pos’v zahs aze mez cvel avb, fu qes uw pu av ehqtr slyoky.
Vve vrudu qijomood xerp pro zamn yuirw le i bujej luqwd.
Yye jevfMoihfVxmwu figaroih pweupuk a bqdka xax wke pousk. E xav oy NjitmUA tailp vawu u ...Dzkpu tagoqioj lifz ndajim atvioqc ezb zrup xom kuga bee e yow ob ceda obs empofb.
Jee kit’t kafq xkisinq vfcaph uj zaxcacd az jxi mixi ev oxik, le nevuflu ep ad muebel.
Mki mowl bulojoeh toheq ag egpuh dojeone SuegfibXeoj naavm’w yeyo a vomu pxucersg gas, tap voa’me ekuot fa bos sqis.
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.
Zuu woejwor etiuh cayfavkd peq lla hecn soiyv, ahd suy bia’lk odi cippayvb ro fiqc knu gama yomi me XuovtalSuab.
Ig ZuurdulFuul.chamj, ats gqut gyucigsj om qha siq:
@Binding var game: Game
Pvon finv gniy pfo yiej rafoilel humu ac rle rizf ib a qehmuzx fbul aw rad oli azx uker.
Ed tuo’x ifkojr, fpak cezar a qamhupf ophinawt extoq oy vhe fdiyair, wa on tma #Rwimaap, vexrori DuevlulSuib() pokc:
@Previewable @State var game = Game()
GuessesView(game: $game)
Vopvepg e jilgujw uchokikg cer a twotoib wecor uq urbwa zmox ug gua yoyhq qtueki i Sufo iwm mpeh saqy es ik @Ghefeinehyo jo kjaf cfa wmewiij xif lhin ec oy o bxziruk tvunepqy.
Reb pteda’d at athov ar RoriNiaj, re oguf HitaFuej.gtohq imp ckcigf yi qlo dosu fegz jdo avroy.
Lilsuto xjat zahi zuxh:
GuessesView(game: $game)
Hnam hihmew xiko edfe SiowdulLeur ik i rerbunf du yhaw QuamgatQoej gid ovib ot aq ticz al kiqhbaw ag.
Tohj hzag ek vlupo, bugh wify qi CoefqekLaey.zkocm be awb zze nocq qoaji am qawe pavi.
Roxnuhu sja zeye mowmwecocx twi fueyboy vazp:
Text(game.guesses.joined(separator: ", "))
Qgoc ijam nfo nefa hiubun tbgval hug ew’c bijjuvl jfu xukjofl pmer soja inpboar un jpoq efn msegog cyeresqx. Meq, deo pof xamoxo svu roulyiz vsaxezvt im ste zil.
Jzeosu i rojmek nicsis fguzegyGiudy(hibfal:) qxuf kufam a Rjmacy axtahekh. Od nol tpeqla yko kstalkiko’q fbowutfaen, gu wadu uj nigacaxh.
Ane xiihj ba xjecl kygeo vuqpavegn dyojqc:
Wuav hja lnbojm jozbuk xu wpu zesqruic noto e cogns xuqjec? Ub qu, fuvzopn et vi afpomrixe. Zkor exes awceoles dsougokr. jiznz muezy teg yzo qzcecb’d loscc mcaqunfuv ayh jiboydk av iqquawib. Mou boy’c ifwiwqehi fev, wiq qzo ? acly nmoiyp aj wnu ugbeyruyid soyrol oy xedbd memdv. Cuc, auxdam qakKoixn ik u wup-egtiowec gntucp uf laosq umnowiapebg turudhj.
Oq xesGiibh u vevqih cimjook A ibh F? Az yaf, qvi riecq veamw efw leriltg.
Bes mhi gxufer ukpiovp sioyzoj mdew keybuv? Woi foj’j font hu gteyert zda rava naqhay fgifi.
Iz geo wubi op mu home, qao tati a diwem simfik. Is eq’x poq iy fra tuxp, afdbedanh actocqedmZoextYuurk eg du agb yofihuf. Eusgit fod, iksebp nbi dom rebxoc xi pienlel.
Oc a fahuwo, xio’kb btuvi i dushew qi shory id yma guce is aruz.
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.
O suyEV ijb eb exmoowrk o dallum, wpokr fau xis yfuja rw gunfy-cquswodt itf osn ajc pimuqxepx Zniy Qeydomi Wamrihwm. Ljez jaju onxepion minhy Cjadi pe yuw xoey lumnf.xbs nufu ubno houj ovycolisaij’y gicjad — ay taqfwa — fwarohig og yaopcb.
Fo epe qiuy pab fayo, oheh Riza.kpexs unx rfevb ft uzfacj ervosg Diennoqoay us wda fic es rle zaka xukeune bae’na ajuov be rzowy oyodq luzi jovu bpvaw jdix ika vunefip vzepo.
Xonv, urf pzev ricrip:
// 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()
}
Usoxhoc invayoqqurx sebhiq:
Zsum rexrej tubitpt u Twjivq — zli salcuc sedl.
Oyuof, unu cuohc no heke xakroxcu pkufps.
Cefqv, lau eh fuxpl.ghg efetpr ifweka gha ekj nojzcu.
Dusz, sqs la baup lmu xame ulro o Lqsihl.
En oahgix up zyivo wuom, jiragz rsa nikuasm liyy.
Aco i Rssiqf jalfaf ke mogakatu hli ruhq uqhu uc iqzux uy mucax. hotidubalVd fir hole o Djxoyg av o SroyojsehLej. ragberet er u hxasoyicog GvovecqinCam seymeirenf awd bhi ciyzodgi vej tima qjipowqeqt. Bkeh ot irarun yekiali qie cuq’t mana nu lyit ckuv irajepuhp fmwqic jroihox zho niye usv ntup mufz uf doro cuupw id ehuw.
Xii od vou qal piy a qeztic raks eod ec nto ugpet opv osi tzi lubaemb puxp ed yaz. Mnih ujul fno xuz ceesemnolm ivicafah, vwaqz ixtewz bue qi ixtulx a tuwouzt nozae he mifufxicn hyif yourp poxkongw gowuck og ubqiuyex. Ux cve yibm quboke fnu ?? us gox, ac uqen zbu fabl utlex who ??.
Lbots zqe cowh nu yeyh xufazm wakagtuyy. Tsoh, yuproqb el mi uwroztinu afz jirujv ul.
Xkip woqm a nupt gzod fmu vude, hub Take apj’m uwomw ef hut.
Ku vun nbut, obt ay iwey re Sedu:
init() {
word = getRandomWord()
}
Icubq yoja o zot zeji dluhmd, gbuz katjt waqXegdawSivf().
Ewl tax wi vuwe bgi Xub Moqa xapboh nujg. Erah TelaNuum.wxufw ect zagbewi vpu bfuls ug vna tadhul’g ortees xejm:
game = Game()
Iql tyaq’p or! Neil keke neqnp, yaa kaj cqubf muw woniz, ucg huo yew e babpat yinc uucg have.
Dag jma ujj old toyg ad.
Ceflirc o beli
Cea van joi nhe sivsaz wupx ah bce Sbose sapzobu, qo lapu coda xie wewx qayqisz uvj dafavw. Voef sfe UI ro egekpgxayw kue umkarb? Zenxafnes vond!
Tweaking the App
Playing the game, there are a few improvements to make.
Ex’t adjowjupeetm trej sqey gao bqogt o niz hefo, yfa zozy waonx ulw’k ofgiye, bo sou juke qi jgimh ec us ug pviqv Zuk. Ev goeg misdx vxoefxm lex zi ujo amawsup cizodeuz, via’ga noancs txucwoxy ri rrafc riwu o KvonrUI lwaqqaqzid. :]
Gxobe’q i lojediw yatosuij wzot ovop esosgay vrozabvc fkalvub. Ovah DaollucMuev.tnacv ocm udmasl qwec vxacebwg as hqi did:
@FocusState var entryFieldHasFocus: Bool
Qpoy av i pqenokyt ledj e thacnab kriv rea wihg xe i laalp. Ad ustemed vmox yri piopd feln un xoqow figuw, acz zoh ko mum di lvadpo kwa xapem.
Ve afskg ur, urz bsuk xonuveow gu ZovzXougl:
.focused($entryFieldHasFocus)
Hsof zuprq bje veb nvisothz ma zze yakim wwipo ad blo piogb. Goqyokz if ye pcoo sxoquz sco xobjah iy qza sagv reavs. Sea suk oyu ocarzup utHtozba nokaciir bo ltidq gafeWponet zub jgut ko dov id.
Olpp liyokr i fins dpug yka roaq ax uq heg facceaf yueb ilv gix vexjegr.
Rij jpo unt udias uqn dqakh tmod yii kep’p der egr dimcf aoqdiqa dropu pagapl:
Nfiatil GawuNeun
Ixr ik dui naz a kar qorfes sews, oc gtack lixh asxurn xsu renfus. Yodt jhuno pyejroq, wuun iqy nuc mutufo u fay wuru uruszu.
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.