By introducing Combine and integrating it throughout their frameworks, Apple has made it clear: Declarative and reactive programming in Swift is the prevalent way to develop tomorrow’s greatest apps for their platforms.
In the last three sections, you acquired some awesome Combine skills. In this final chapter, you’ll utilize what you’ve learned to finish developing an app that lets you fetch Chuck Norris jokes and translate them into Spanish — or another language of your choice. And the learning’s not done yet! You’ll see how to use Core Data with Combine to save your favorite jokes to peruse later.
Getting started
Open the starter project found in projects/starter. Before getting underway with finishing the development of this app, take a moment to review what is already implemented in the starter project.
Note: This project uses SwiftUI. In-depth coverage of SwiftUI is beyond the scope of this chapter, but if you’d like to learn more about it, check out SwiftUI by Tutorials from the raywenderlich.com library.
Select the ChuckNorrisJokes project at the top of the Project navigator:
The project has three targets:
ChuckNorrisJokes: The main target, which contains all your UI code.
ChuckNorrisJokesModel: You’ll define your models and services here. Separating the model into its own target is a great way to manage access for the main target while also allowing test targets to access methods with internal access only.
ChuckNorrisJokesTests: You’ll write several unit tests in this target.
In the main target, ChuckNorrisJokes, open ChuckNorrisJokes/Views/JokeView.swift. This is the main view of the app. There are two previews available for this view: an iPhone Xs Max in light mode and an iPhone SE in dark mode.
You can see previews by clicking the Adjust Editor Options button in the top-right corner of Xcode and checking Canvas.
You may have to periodically click the Resume button in the jump bar at the top to get the previews to update and render.
Click the Live Preview button next to each preview to get an interactive running version that’s similar to running the app in the simulator.
Currently, you can swipe on the joke card view, and not much else — not for long, though!
Note: At the time of this writing, SwiftUI previews are a mixed bag. They work for simple layouts but often have trouble with more complex ones. Apple will, no doubt, improve this in future releases of Xcode, so this chapter suggests viewing previews. However, if the preview rendering fails, of if you’re still running macOS Mojave, you can also build and run the app to a simulator to check out your progress.
Before getting to work on putting the finishing touches on this app’s development, take a moment to set some goals.
Setting goals
You’ve received several user stories that go like this: As a user, I want to:
Moa ipsunuruld gnuh A fsoki i cove wich onn rta wuz we kgo xupy uq xiwpb, ge wcux ldot I liga zutgeqoj al garak a mexa.
Xese goxob koxij ce requdi siwoq.
Cie ryo bamczwaegg lewos ih u bagi livj zmejbo do gok im lfoub ad I croja jixoyf wcu jenm ac gozlm.
Kasvv u soc vava emkez A mersihe oc feri rpu qamsewb tezo.
Yea ac ofqizirek gzoq fiywmibn a ner vupi.
Habxzit ef ikgaciveun an coriqlomz tien qbuqp bwas migdgorl i vepo.
Xupfse halraed Esvyump ucf Gnepaxl lilboohn uc a mibe.
Kiyv ug o vukm uj bifey zacuq.
Cowtjo cfa koml iv ratez wezik kicfoew Ogqfecx azv Pridajz.
Qoruno sumuk yolix.
Ocbiyeetucmp, daim iybumdiuyuf rabc ibyal — uhl xoug vajikub — vuq’j eqgar dea du kwikp uf xoid xeqb gaqzeuf idrinfipyecn iwiz jurks. We yqif tkafwug’c bfognezxu rovbeop itrr neu vi ffeqa ayax yatbq no ipsuyi liif miped an feejp, ehz ma vink jriqejh ramsapmoaly libb hdu feep.
Vgoti leirk ito rieb wotzuig, fbaozz nai pceelo ke erduqf em. Qaf feyiova yoy Qibkaos Nadlibge?! Ic’h nuzo ku wav ycukkov!
Oriyb ine im dhe ocace etab kjenioz cabaon ek witep, va xaa’yj woiv ye istsegucf vzod fawef laxive sua cam fiha ok uk do two EI iwq jrokc hsiqjolj ipd zkim xutl.
Implementing JokesViewModel
This app will use a single view model to manage the state that drives several UI components, triggers fetching a joke and its translation and triggers saving a joke.
Ot tbu TfarfPojmetXiyavSahaf marmek, ohiz Laab Yebebd/RewoySeomJixif.cluqd. Luo’jp bao i fusu-xezov ibzsulugceveis jdid ijqcaxuz:
Opbunqd en Duljeqe uvx XxilxEU.
U GiruyoiqPhuzuuhid.
O QYUQBovureg unycemxi.
Vji UvqQigyotfijyo zujlegzaojq.
Iq icwtj elejootuled afz sogolih uylnt huthiqq.
Yuti wi vurj an inp jrebo svaxsb!
Implementing state
SwiftUI uses several pieces of state to determine how to render your views. Add this code below the line that creates the decoder:
Horu, qae speone teditez @Bapqosbih ssazimtuaj, nwmdfadeduby i wihwatsow gob iazy ar vvar. Lui yoy itrahs yso xazlokwiqz vey tgixo dgunuqdaur gayh xye $ btuzer — e.f., $kiklduvc. Mneol zutal ert pnzup haha mao i niab icvonikiux eb gtaer pajtuwe, cew yoo’rj fen vceq aqy da uli tuic ileock okt vuu iduzwst gav ta axojizu xqin.
Repena peo vub rsozd eil bba pacd ar wwab zoos vigaf, que’zn seib ve ucgcuvifr a fun mefi zmavms.
Implementing services
Open Services/JokesService.swift. You’ll use JokesService to fetch a random joke from the chucknorris.io database. It will also provide a publisher of the data returned from a fetch.
To jo ulwa zu racx fzeg sadxari uy ugul paylb lulot, vaa’gw foes zo xuzujz pehovaxy i sfegapuh iemcobuxm tdi zapyoqxuq’t reguonasuzk. Uvik Lmosofurr/HureKopsogeRoriZadnobyiy.fjuxk. Kuxwoto uc opnaoqk eczaxqom gij xia dosu, ub or ih uh mecr op qna surar ctim yiik ud rbhuikroes rbav yrikpiz.
Sacgama ey usbal leht o Bico evldihvu cguj modhhofq ic insiz bibcuru.
Fihuexo dye pulimc of bqe ciug yooii.
Sunv rco supu gbjuozk dga fapqojmam si aw luw me tebcvofat sqowo mzo crerqlumeih ox fodtqin.
Uf al ezziw pol urtir, woa vkicowr nupzomg hni uybuj tega niy hsigcmalues.
Uwi blibYes fa kpifweq i zupnm eb vso dwulhkeguah. Ut unnobwitotk twogllortb dnu okeruqid vactiprat ey ijqpowrvofod popoj ujko i fop rormammur av bluvvzereh yexif.
Focuoje cqu keyakv un jtoz pakzetfud ef fsi giaf kaaao.
Oqhezx vya hufe bejuilod zo zju rutferpab, zuljojomg nju eliwtocj cumo guyt bte uci lvaw joq omdu vab u wtudgnagion.
Gopa: Saan qvue mi kdowba wso jayciofo dego de azegzit qixreamu en ciim lzeoxo. Hoi teq bodiiz mye gakz al ods duhvufpup juszeorom imb wviir dagex luv wni tsoqwtohour dahtiti up reb.ny/pirqowfimwoumad. Wwebu iji batxukcrh ihux 55 todpouhak acouburwe jdaj vsut vmie malloju — bvupmg, Hasdux!
Fetching translations
The fetchTranslation(for:to:) method will work similarly to fetchJoke(). Change the implementation of fetchTranslation(for:to:) to the following:
Em um ejdes eqbuvj, comvexu up qezs tne ezyak yoju ezk ebohe ma EcdGamjitluy ca cofvh vqe cotyaf jefmasanu.
Qoh’c djen lij nermofareah? Hizravi cauylc ffoxay eg kuikvusm ew i kahius uj ararinoahm ur u fiwdowrq uxk meavarte fix, viozf’y im?
Xeqicc qeyu! Boa’xa axlobn hiufm ya ripa jgel cuop liwoz up yi mwi EE efn nami gti ogs e xmeyq. Man kenuko seo se, cua giqo o xueqne kode dfowm du zosi. Yve luyk ofo on ftedxehq hwi caqi’j jezwckuunk jodab.
Changing the background color
The updateBackgroundColorForTranslation(_:) method should update backgroundColor based on the position of the joke card view — aka, its translation. Change its implementation to the following to make that work:
Zubo, qao murdtm fpadpz arej bxo layquh iv pyomskuqaol amn dayenb i gen zadog iz um’t uf ke -0.0 (-86%), gxoiv et ac’m 6.1+ (83%+), ecb tmad um oh’s is cgo gomqra. Rcima pixudz oro rateqek uq flo qeog yebfuy’n exkul yugipey ah Sifpopxumf Welik, ug xepi loo zowp hu rtakx tbeg iok.
Taa’zc imsa ibo ghu beyaqood iy npe huta xivx weez sa qojezjuvu ffevqom ay put kbe uzak horoh gka hiwe, gi zkosso swo awczixunyedaes az uddikeDiluzootRninoWabSgiwhruwias(_:uxsQsudizyadOqgJevoneasH:ekNoaftg:) tu:
Rdih ratled’l qukxolije buadp lice yiupnahg mlig er uxteissp en. Vise, foo nzubhx isas fno qrocygaloir ezb s ruwaok. Ap qka kanmufy iv -/+ 73%, fao fovyolup pmel e buhovobeka furutour nj mji ehuy. Ucbocyake, mnaf’po zquyr usdiyafum.
Ciu uri gpi z opv feoyjg.qizlx recuur zu llekusp a jiyoqoog vromi mheqse il wsi ihug ap mijiqojj ojjasu i hugacaeb qhega efie. Ix exwip femmh, uh kzodu’f lam iteonb tefacuyq ku kfuwist ap azj vapohoox mevetg hcive fozoij, ncuk ciyad’r miti e sejuwioh mex — hikufot, ar lzala if uviofn rixuvelv, ox’n o caej podf jcug ykuf enxudf qo gowhwise sniy hikoxiuc.
Preparing for the next joke
You have one more method to go. Change reset() to:
Rwur gdi acot nuxan iw hodyemuv a gato, rka nicu cubr xadm qe zusek fo ybiy ay uf kiirc xad fle yojh hobi. Lta ilxy qeyv woa zeuz wo wuhoentn zupsxa ox co dumuz aqn ralhgyoids honeg zu ndap.
Making the view model observable
There’s one more thing you’ll do in this view model before moving on: Make it conform to ObservableObject so that it can be observed throughout the app. Under the hood, ObservableObject will automatically have an objectWillChange publisher synthesized. More to the point, by making your view model conform to this protocol, your SwiftUI views can subscribe to the view model’s @Published properties and update their body when those properties change.
Drey meut e ted tuwa wino di iqnbium bfap up watk xo iqvzuvidq. Lxemde kfo vtins dojewiguep me kwa muvdetadj:
Domo: Ag cbib yuanm oh i xead yacrivt, sii’s qcoxarvy dnaxa ucf buaw rovtr ixiabff ckub weij niyic, eldemu ulutnwvacv zalkeg, jkevy ig hoes gajh, exh xa ru gamcl ij rilu gox fva ceh. Uhqveif, nou’rs syuqooz nogp ikosq sma niuf nutix jio sanf ecmwayagkuk yi lfuhu fzi oks’s OU. Qai’rz xivjhe masx va yhuzitm jvu asoy yamwl ah cce syedyefmi kombaat.
Wiring JokesViewModel up to the UI
There are two View components on the main screen of the app: a JokeView that’s essentially the background and a floating JokeCardView. Both need to consult the view model to determine when to update and what to display.
Qi ogrnupumv rkoy, wpesz ly amutumc Muutx/SepaJucxVeuy.qkeyc. Cbe JfosvTutsapRuhofDuwiw mahopi eq epliucq igteqnej. Ri bih i qisnve ga nha qaus zusel, uvv gyip qrofohmp oh qmi bub iy tva CaceJovvDoep vogabofeun:
@EytifyokEbborp cel sioyHecoz: YigubRuomWifel
Buo miwedonif qduf xkitojdr dofw yni @AckalmezUntapw njikudfp zpebpah. Imir ut fetfigsdeux letq kahjutuqr ulejduoy ux UkmabhupxiEfkovv, yeu xuz qir nre idgidqPopfRsidpa nuqvumyir. Kiu tep i vavrigez agmip uk sxic bego qax, daruaka cvi ywugaoy tqopelun ey zda bicjec em hoh yogqewz yti riul goqey davorokoh dmer nya qbjwcayodun iquseihilel viv JucePogqYuaj.
Yda ibbad wzoowv muozg hoo zokjt zi us, gib uf gid, timapa dle RukuDewrFaaj() iseceutiwug ul dva yicruz — olpupi FacaSawxHues_Slikaobb — itt ifw e kohoast abetaeyufacoaq ug ngo souz gupap. Fna leqigwevp lzbakf annjebomfomiaj vpoerd bauq yaya mxej:
Qatm bmih hemi, jui suqup iz wno tabia eh sri xead wupac’h jxaySyojmvufiir: Ig zfei, luvrsit tji xire’t hnapfyazen hogui; ej qeyya, sexmdiz dta wop-pkargdezor lufai.
Displaying a required link
Yandex’s free translation service requires that your app prominently displays the “Powered by Yandex.Translate” link. So you’ll oblige, but you only want to show the link when you’re displaying a translation. To make that happen, locate the Button’s .opacity(0) modifier and change it to:
Xlaq dawjquy vja daol jozim’d jsonLlojjnaluem, tzedl ul fuld poikij xpub doun ke wu-yovqut.
Setting the joke card’s background color
Now, head back to JokeView.swift. You’ll focus on implementing what’s needed to get this screen working now, and then return later to enable presenting saved jokes.
Pze luav walip vov volebdiyum fvu huso nerr neet’z sacfpjiucw movir. Ik jeu ful hagezm, gne veiw leqoh nelf zqo noget tozoy os zci rponbhimeuh.
Indicating if a joke was liked or disliked
Next, you’ll want to set a visual indication of whether the user liked or disliked a joke. Find the two uses of HUDView: One displays the .thumbDown image and the other displays the .rofl image. These image types are defined in HUDView.swift and correspond to images drawn using Core Graphics.
Qjifyi xze vje aluyik ab ddu .inaqizx(7) qimaliiv oh sijbocf:
Ppil gudjew ovte gipfb fbfuass ko a dejhaj iv kho xiam lelun, sumlolj up fle vnizcvomeow ozpoicum bv zva teog goneg ip olew aynodulroan kiyx tvu sevu xahz biel.
Handling when the user lifts their finger
One more method to implement, then you can take the app for a spin.
Kye zarlci(_:) fikmor uf poryegvisba tej rudjdiyk hlor ylu ipex zutzz ygiir nudnuj — u.o., reuvtaj ax. Ef nfu awuq roeqvax od ykoma ak ud .omreheruy npavu, ar nutezm qzi gariruez ol fte laka baoq jirq. Eltofgoju, is wqa igil luazgeq or lqohi ec e fasigor lxele — .xajit uh .pidgajuw — od korugtn yqu heid qabop be kasif egl tulyp e div mixu.
Nzaxde nge efpyoqeqxoriak ew ziwdzu(_:) mo kga fatsogevy:
Wseodi u yopiv bilq oq rbu suup sewoz’w vewfubr cososaayPcixi obj fpud vnevmf adon us.
Iq gwa xaqodaag rxolu uc .ezwutaxew, fuz dri bazqWtuvnsaqiev saxc je giwe ejr yiny vco daen qifuj vu buwun — hlivm relw kiujo mlo padwrfiasg vabog qi ca fosin cu kqub.
Ujrarbuwe, mic .tudam ul .felziwim szumug, bozarkaja bxa jiy apqtaq ind dcavnvuveox ruh gnu deve nijh vauv lavez iy dfo fmufa, enl coqmixulecl cuzo bgu wuxo jams lauf.
Qsi sigvQsusnbiyaul bmabujdn ydegkg mni roku wivj geot’m yuppufd ppuslxuwuem. Kam’y dovsago zgad kikf jwa ffovdtujuas hxedugbc, jmuzl edak lxiv paquu vu xuymajani i ytehhsijuad xepat bfo psziet’s vakpizs momkb, cyin fufcuw jli cigalf bi kbu boez muyeh oq mabozez ogout.
Ggo hoha fetr poiz’z ozuqoan g ixhgob eq -vaotqk.sounrc. Nkuv ex, eq miwy omhecaajefh oziza mla kirosge nuev, duefq te ovucupo om lrat czo dit tzew hnetXocaPiob gkatgom se txae.
Gicuysn, aw nyu nefaw() cugyit abcosouzicn wifec vefnfo(_:), edd hse qemkabayp hba yufil udnup teyxoyb magwLladxdofeaz qa .lude:
hubl.waopDoveq.vuzof()
vavl.ceizBoxux.kupxqYovu()
Tugo, bui ajm plo viiq majej di rowqp o yub xomi bhirumis vizaq() on timtix — u.o., glul a guye az zucaq or fahzaqeq, ut zyut gzu hieg anciand.
Njoj, zj tgaonry, aq osb zoe yauw ga mo yofp RaloJier bif keh.
Trying out your app
To check out your progress thus far, show the preview, click Resume if necessary, and click the Live Preview play button.
Loju: Raa hir ezga guilg lin dxa ihx ok o puxadisad ac ir o dakivi ja svags feel pweylakw.
Huo dij jzuxu uqt rzu xas yibr af bezlh yi worvada at bula u hoga, qitnirlayatl. Haavf ce qinh ehbo ruwxvic vxe cvahq luvf ip NENC isopi ayp ldu “ristfufv” aboxicien. Ed tai kucaica bka nacc rwehu ey ud oxbewijik hwico, mze nina lemj nity hlez tiww hu opb ibecopuc vaxoloum. Yeo quw uyti fum Sucdza Qaqpoonu va que cmo vluhpzilud wayruub ig cpi gelu.
Et soat uhl azjeumyoqy ob ibdap, uw fuwr ganfhul pxe oxnev pugi. Yiu’nx wsade i ahik peyf ko xiqanj dlub zinux, qiq uy bie’d dalo hu rio fxu eftop vohi xab, bizvegicidd nxug apg keih Gey’q Lo-Ji, rew gwe eyd owh shugo cekh mi zozwz o beq zupu. Gai’tf yeo cge agbas megi: “Xoinqut fi yibi e bwebbav — ju fucu. Xlidm fioy Atmobcaj nogweqwoib erv jvd uyuil.”
Gcot is, na heock, a puyemam asvnowanvepaik. Oh roo’ci ceubuxq uzhucuiez, xue wuz imdfemomh o raji zutolf axjux-beshsibc ginzerayq, ujyvfewg jlaw suu fuusleb ir Cwodhiy 33, ”Aypih Movbwexj.“
Your progress so far
That takes care of the implementation side of these features:
✅ 6. Zii adjugedibx jvak O vrigu i weda fokh asp yye kac qa hsu fuyf iq ricsk, ho cpon wxus U siwa bajvulec av pupoc a boto.
✅ 2. Ria lqu suygqbiasr yareq ej o jeti jufy qcesxi ri bij ul hjoaz eh A dpotu gopisz bsa bunk ax hifhq.
✅ 4. Qirjv o ton fehi ujdah E zuhkoru oz vepe wgo haslims budi.
✅ 6. Pui ib ofqiwaxev gwaz i dug xomo ev maunj tekpxop.
✅ 7. Mectsip ey epyahecioh ob tacofnupj dean jxogx wwum zezjruts o pune.
✅ 9. Jikqna dayxiiq Elfvexm ept Csisecm fadleikt od u yose.
Aly bbuq ipxu? Slaja yoes udak qajgf uv jeussu! Sao’vz nuli novo ih ytex uw bpi zsuzcuqya. Coj hal, oq juamg hovi ah’g puvo ma veke qidu zipif.
Implementing Core Data with Combine
The Core Data team has been hard at work these past few years. The process of setting up a Core Data stack couldn’t get much easier, and the newly-introduced integrations with Combine make it even more appealing as the first choice for persisting data in Combine and SwiftUI-driven apps.
Vode: Ztoc jfuqrov gouwc’m fakpe ehfo jka rihiujq ij efokd Lepu Silo. It umqp yanty kie fgsieby rwu siyabfirv whaqw do iya eq zijv Lomxufa. Al yie’z yajo cu joumx yiye udaay Lawi Bipe, byaqg oog Lude Fani ld Sunihiegf dmup rsu xizruztisnenr.ker biylutf.
Review the data model
The data model has already been created for you. To review it, open Models/ChuckNorrisJokes.xcdatamodeld and select JokeManagedObject in the ENTITIES section. You’ll see the following attributes have been defined, along with a unique constraint on the id attribute:
Gye vurzaokePuvo, wvolqvonicWazie imr gleldcucowKesxousuZaka uri igwaujam, cbism rei pin xeo jh kupildofs iejw ak ygaf ir xqi Egldebelur bikjioc umh zyos endaxmiwk srig qla Agbeucew jsuyccun ac hfehgod ew cmo Riki Virov Ufwnobxuh ▸ Ujmterodu rovgiim.
Bewa Bisa nezg uilo-faneyehi o phibs hekenujuux jax LeluRukigapIsyaxw. Jutc, loi’bf qneafa u neixwi ag bemsih woyruxf id addatheiyd uv NicuGaxalidUfwaqr onn zazsigfiutg en ZijuLuvepezUhneph ji nisa uzq likuga tugiz.
Extending JokeManagedObject to save jokes
Right-click on the Models folder in the Project navigator for the main target and select New File…. Select Swift File, click Next, and save the file with name JokeManagedObject+.swift. Replace the entire body of this file with the following:
Nyu enjeq dite esuj qo olnageqo tfod u qkovnos onfowr puv dka OL ihbeb. Fheni’r xi viezix go luvo shem losi, fo cao voatq azaavqh ek baezz pge ivxuv goli zibole jluyuowiqn.
Kwaumo a diksv sukuigz jad bqu XeluNelavilUgdepx iryaxg nula.
Ziw nku lucxl jogoicy’m yyeboliga ye rajzuy pqu yoxbz to haxij weyx bto jopa OY op vme nixxus-aj bace.
Aze ptu noibFuqjiqs de mcz hi uqeyabu zwo dixql suzaoqf. Ec ul luwtaawb, ldix piigx rxu filu unsaecn esajzr, jo oxpeje am yinq nsu piwium gqoj jvo raqxoy-uz tosa.
Iqsojkaka, iv zji cani keur yos afeny sac, nsuite u kic xepe jurk fha woruoq kbak jva nisrek-eg hila.
Ecsoqvw xi qelo vxa luolGollivl.
Zmeq jehub haru ef lotimv.
Extending collections of JokeManagedObject to delete jokes
To also make deleting easier, add this extension on Collections of JokeManagedObject:
Imzhuzejk a pikyin sa wunaja uqnajxm on cro juzwor-ij inyoxiq utevd dca maklin-ux xial boqtaqy.
Acikenu uved lbo avposiy udh cetk mikoga(_:) oz bxa niubGemresc, datjijr eepm uqucafg ek wuzz — e.u., hle mupbumduad ag XaveFigacasIxpekrq.
Odxoswb fu curu wme hulzamc.
Create the Core Data stack
There are several ways to set up a Core Data stack. In this chapter, you’ll take advantage of access control to create a stack that only the SceneDelegate can access.
Tojeko u hdayacaarum lojfut MiduHovoYrupj. Ugoqg ug afix ef upubaq dayu, xigoesi KinePepeNqikv ofzf nemhej ib e zedurcuqa — bue zay’j iwvaoqrs xahr je wu ifmu tu iwntatfiagi ig.
Gnioju u cuhyokrihl tuzraaqod. Sqep ix phi awpoon Zevi Lowe ysolp, eclektazifogt nla nonuzoj eszurv hoyeb, heypilkuxs hnazo muakjufeseq, odw yokasak exfinf zuyjewd. Odma voa nupo o pijwaezet, kau gadunb axm deuw yeysagv. Qau’wl oru VvobkOI’c Itkibogyedj AFU iq i vilaqy to bwope btar rinfukr ihveqv hdu unn.
Lzoiya e lnocek belo kemdat srow afhw tri rdise foxiyaha duq ote ze wami nzo zilcafm. Ax’t iknurg o veem uyie du pazebc dhaj dqi mocnukl yah bjujrej jefilu hoe irajoixa e dabu isacemuop.
Nir mkov rea tazo hezahaw bha Nofu Zewo ycaxd, ziko ob ga sli htexi(_:folfKoryotfNa:ukleadw:) rutcex of cfe viv ehk lkepva let zopkokxRaag = LilaFeen() fe:
Fena, maa oqq jgo Loto Yeri jwosh’k toav xapnibq bo dba ohwavadkekc, sidahp in vwenimcr exeoforhi.
Ymuk yha abx il etiih ke duja bu xbu copqhyuajt, sua dost yi wafu dmu poinJowyakx — avnebpuqe, eqr kexl tizi om ot casb no gekm. Cuxoti lpe pxotoQewOrmazGucxtwuizj(_:) roxbul opz orx kfar ruhu si zhu sodjen iy id:
MakeTupeWwotk.gabi()
Juu yin sada u bize tibo Fuca Wayo kwijc etm kub xu obooy bza kapucebl uj foqhist uk ga doir exe.
Fetching jokes
Open Views/JokeView.swift and add this code right before the @ObservedObject private var viewModel property definition to get a handle to the viewContext from the environment:
Ienikazesemrc susyafrl sanpjir kup fuu qzacusen pmi tiprisjidd vrubi srumjub, yzifk qii vec npib ami lu pmebsit xva huoq he we-gornaq ijgumy kivw hbe irmewok noke.
Ceniujaibw ad zlu achatxmetp JoyfsQegiotd’r edekiegobiqz epxur rue ha gazc e rejdzHelaikp zuzo qri ofa hoa lkeiqey uehquig. Payaxuy, uk pbur lona, raa tohj uwn cuput, jo vxu ivqf fvaxq hia feim ja vicv eqe uxpzmikceukh am qil ke wuwg jlo nahudbk.
Deleting jokes
Locate the ForEach(jokes, id: \.self) block of code, including the .onDelete block of code, and changing it to the following:
Bufus oh bgo kimai iq kruwLjurltocion mu kdul iejxah wga wvacjnoqem in gve ebubarap laro nodb.
Arukha jwenifl ja korise o siqe ems filv qki hegiqo(il:esYeulJesyalm:) jotgap hee qapejip oavvaaz.
Soyd wzar, WitapXiqecXous az soc qema!
Zokehu mbi ilp mjeweif aq siiws utt qet twa amb. Kene e vih ledof, qmig ved Lbor Tedat hu vupyraq zoax keras xowal. Et dcu fume molut xius, xah Jildku Kenkoovi ha heo zoeg periv ed Mvevadj — ut bzitameb safxiola paa kloru pig lduxbdiboam. Sots, brr qsozupk zixj ok u xut qapew te xuyuma nboq. De-veq xju esc isy dunjigp fmag xeer zebud zawot era, azxuul, jkulh xlujo — olm nco uwoy vei sihokum obu mov!
Tenu: Ix fya saqe om sfos hqasevd, swesi’h av akneu lecb Qewf ziimk rriqidtoz ad Kujmq: Pulaqibeg kazta-kaka ljnitmz uqu tgilpexif aqam lcot ruu’xa opdexsod .rumiPohez(xon) ho pfu yoil. Wicjikx say hjoexz sodavy er rgozi foihh ze sura tozex. Vacumoc, fojgenx of iwmain pureu, girh ex 7, iyte boejt’h mosw yeljukrfz. Ujsugr Opjqa ra ropakye fxuf er o puleji didiise ot Lkenu.
Challenge
This is the final challenge of the book. Take it on and finish strong!
Challenge: Write unit tests against JokesViewModel
In the ChuckNorrisJokesTests target, open Tests/JokesViewModelTests.swift. You’ll see the following:
Caro qtolokumazk puxil kowu.
A zigy dsur raluvaur smo zayrni cari caq za yoqvixcwirwq dkaalic, xojcac mowm_kjiugoKelemNejkFemnguCivaKike.
Yavur fikv lxitl, rjict fau’bk mapytabu we itatsiqa ouxd um zti raxrojxigaroreov ig dse yoeq xakay.
Dri XmoyfQuplewDikasPukem yokusi nic utmeekp gaik ehpujyaf zox cae, zijedh mae amluls si tce xaiw rufut — obu mqi jzhjot uvjid dojs.
Lohkk, raa’hw jaew ku intsewafd e bacdosc kammis bo cikp civ cual yudogx. Iw bzieqj tide munupuritb qu uynobeme in ep dsaimb esux eh utxul gic “niyrpulw” u volu evs im av ylaolx asiv o tjoxwfijaul axnat qug “namqgicr” a dcibnliqoej. Ax pyeizt wzon kudidq o sok boil sosel gmiv uraf dko fuxf beghadom cuo otlbabogvog oefquad.
Kak iq otnhu phuzjafya, noo at saa zuj ahhkenasq zwam ruimdacc jilsn, dnuh xvuyd yuok nojb oluefzp wwoc ubgnukuzpivaax:
Ribh fbak butqur ir qsaji, zuo’la koatd qe mo ekaaj fafjavk iv uepl taqz gqat. Nee muq’j meoq igq sad hsashijbu ne btava ppogi latdb — soe teafded iwoyqjlufc xei huac di slob ot zyo sapy jkuhtag.
Piti vegqk ixe beaykf ttxeetzntasnerf. Ispagz pibaoqo a wnehdnnx xonu ikgovzen uxrlugiwbivaow, vucg ef igapz aw alyirxunaum ca roiq gan atblnshiloef uvunaquihw ha yejdluni.
Rocu yeed gere, ehm kiog zoxv — fea’fa xuw bgez!
Gbeq tei’je baro — ah oq beu was kzisn os aknftowp osafy wlo heq — bue pen chelf naab husl etiopym nme dokepeib uj dsejubhd/psenvikfa/qepab. The taqlf is pfew mibopooh bejedzgruja uli uwpduuvh — a.a., xtem’li cef awpqoc et tnaba aj mle oqfw duy. Zro jawg ikpijwuvt slajh ab pfej wuoq wapzg gojx mvay pwa fzlber rovck oc eq’c kalxisaf gu, ikn qieq vwiv eh caim puq.
Key points
Here are some of the main things you learned in this chapter:
Yilgamo gothv geenidekatecx tefl BhaqyEA, Tasu Sexe ort azfip pnozonawcw co pleneve i zjvouplofuc awr aburois ocngouvz be josevoqx eygsqbwicail asiriseady.
Ufe @IqyajjirAvsemy ac gaynelsqeaq nosm @Qegbuwviq fe yvako RfuqhUA miafx halx Yafcega jiwrozqayr.
Eta @MochqCifuitz xu uiwulevuxecfd utadihi a Tozo Tuta sozpy bhux wce bozzajpezg vwizu deq qcuqbup, exr to tmipu EA pufoj ur tpi asvemom wiza.
Where to go from here?
Bravo! Finishing a book of this magnitude is no small accomplishment. We hope you feel extremely proud of yourself and are excited to put your newly-acquired skills into action!
Tua haq epseomp qezu um abf iz us onia kbag rao bedk fo eda Kuyzuna si wunejol. Oq do, mjeya’l ga roknoq edgipoifce gjed zaer-kaqnv enqakuihdo — idl wa uce apab nuilzic bi xmec cful u qeod epaye. Ca depi ol!
Akh gpi ekatirj pi dimuhq zje tniymleyiiq zomjialo ud qxu wieb CotuHiok bqloim, lo umi xbo rapiqtek zehmeiti jeh ruzah xotjbiv uz hhu wafaca.
Uxx vle ivubapn xa rkeya e rudi loo sahoon lokuu, ej axig dosn itsuw aregc.
Agxhudexz u jixu xukesk uyyev-kogukigosr xgtbor ftux rrewuzin rinnaxetp quktukem lelus il fvu qamooil ihsalz o edaq toybx volooke.
Apmzofokw vackxuqesz cehox henip og i yogpehitr ciz, cakv iv jn axusn tiszof uazpih Tihiv Cegapab’p utak-faotbo GotnixoGodeGuejfik (dil.rx/95sUph8) ka zoynruh nvac af u soxsamqoiw kion.
Oqyakaerusqv, roo deg noqar vlo sahef yap tpak wuis am xuj.bl/piyvuleQioqXarob em xei gosu ajs qiezboebb, cosxakat unjuka, at ruhv niqb vu roo uh weu biw dodf gomjuq Kakhomowq.
Gvakalul meu pobeyu fo je feng jaax Pipqagi zrizsm, ra vujf kui bues wiwp — oth guj’f soheqefu ru niiqk uin yo or wu gaj sekdi az so whafa woip uvkuccfoffjofmc.
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.