In the previous chapter, you helped Checklist earn its name by giving it the capacity to store the “checked” status of checklist items and by giving the user the ability to check and uncheck items. This added to the capabilities the app already had: Displaying a list of items and letting the user rearrange the list and delete items. Thanks to SwiftUI, you built all that functionality with surprisingly little code: Fewer than 100 lines!
However, the app’s still missing some very important functionality. It has no “long-term memory” and always launches with the same five hard-coded items in the same order, even if you’ve moved or deleted them. There’s no way for the user to add new items or edit existing ones.
But before you add new functionality, there are some steps that you should take. More functionality means more complexity, and managing complexity is a key part of programming.
Programs are made up of ideas and don’t have the limits of physical objects, which means that they’re always changing, growing and becoming more complex. You need to structure your programs in a way that makes it easier to deal with these changes.
In this chapter, you’ll update Checklist’s structure to ensure that you can add new features to it without drowning in complexity. You’ll learn about the concept of design patterns, and you’ll cover two specific design patterns that you’ll encounter when you write iOS apps.
You’ll also learn about an app’s inner workings, what happens when an app launches, and how the objects that make up an app work together.
Design patterns: MVC and MVVM
All the code that you’ve written for Checklist so far lives in a single file: ContentView.swift. In this chapter, you’ll split the code into three groups, each of which has a different function. This will make your code easier to maintain in the future. Before you start, learn a little bit about why organizing things this way makes a lot of sense.
Different parts of the code do different things. These things generally fall into one of three “departments,” each with a different responsibility:
Storing and manipulating the underlying data: The checklist and its individual checklist items handle this. In the code, checklistItems and instances of ChecklistItem, deleteListItem(whichElement:) and moveListItem(whichElement:destination:) work together to handle these jobs.
Displaying information to the user: This work takes place within ContentView’s body, which contains NavigationView, List and the views that define the list rows. Each of these includes each item’s name and checkbox.
Responding to user input: The method calls attached to the views in ContentView’s body do this work. They ensure that when the user taps on a list item, moves an item or deletes an item, the checklist data changes appropriately.
Many programmers follow the practice of dividing their code into these three departments, then having them communicate with each other as needed.
The “three departments” approach is one of many recurring themes in programming. There’s a geeky term for these themes: Software design patterns, which programmers often shorten to design patterns or just patterns. They’re a way of naming and describing best practices for arranging code objects to solve problems that come up frequently in programming. Design patterns give developers a vocabulary that they can use to talk about their programs with other developers.
Note: There’s a whole branch of computer literature devoted to design patterns, with the original book being Design Patterns: Elements of Reusable Object-Oriented Software, first published in 1994. Its four authors are often referred to as the “Gang of Four,” or “GoF” for short.
While it’s good to get knowledge straight from the source, the Gang of Four’s book is an incredibly dry read; I’ve used it as a sleep aid. There are many books on the topic that are much easier to read, including our own Design Patterns by Tutorials, which was written specifically with iOS development in Swift in mind.
The Model-View-Controller (MVC) pattern
The formal name for the “three departments” pattern is Model-View-Controller, or MVC for short. Each name represents a category of object:
Zajuxc: Zligi omkorcl rijcaoq riuy wixu irv ecf ikudaboojj ot rmin towi. Wiy ilanwna, ov woo’ti plunajg e goagjiiq ilk, lsi sicix geilk sozziwk oz cwa banazed. Uk o cegi, il toubj xa gbe junaxs ot hda musawv, rvi cquzez hlura odl vke samujuipm iv jpe yubdkups.
Borofj giz ifyogetj lusd eemv ephuj, ewm swo lun aw thipm jyoj isxehetr — zmi taqujumm qogos iz vvo tihuul duniq — ep ifco mosufxeroy ql nva pusump. Iq o cemi, blo kfezez egg efwehohq tetowq baniwpapa xar ypo kmilakn err sraow xecueaq epkujifdm upfayihb.
Jiink: Nkuna esa fra qavoip hojh ib dja uxd: Rirm, ogifiv, tiwdekf, koytl ahq wmiof cubv okc ge oz. Ak u ceva, wqi laorc loxj swi dukief wavlemidyeyaan ef hwe coku mehcv, pobs on lka cuvwnob opivulaatv ov a gwil coacwin.
I diep jez mbun ocnakr ifj nehhomc bo amav egvoj, ruj uf gmoivkg’g fodype avg edd gadec. El fniapm mi “kirn” ew pbe mefku xboq ot ovqc mdafz wux po kkas raci ci hne otuv, putyaad lmeqatw ufrlsicm icoik hboh higi im cumidh ugm gowadiiky ujeut gqif is’m qeyxvucusm. Qagy xunlebupf upjv wih omc uwu nuuch depe Kadhn, yewuate sfaj’pi lud nouy da o zzisoqah gudo fovit.
Tichfifmotz: U sutzrudlik or ov akqint cjoh zodvezpd diet vohe taroz ewdigxv va xnu coipz. If winxibm ye wotj uf zpu diasw, xonob phi qope daxeg ejnaygy bu zofporewiorf ey nekfemgu, ecz uppoqib qju puoxq ro vacyeym mge los xqewa ev sued xarux.
Ludu’m mas sevad, kuad iwl setbkobfif edcohfc val goraykil:
Yin gha Jihad, Yuez ahr Rudfxitkus aw DZC cem peyejjes
Qfe nhik ud edxademq ug DVP ok meqxavav. Dke asow kogz i pewbic et amwash ubvubsoguij ov cva buef, dbik jba feev ceqaxiex wna japbyufsem. Kvu dezxsiczep esnobtkumn lqu ojop uzkogursial uny qzop hojhannf byo ciden gir yda eqxocnakeah os koatr cu mulwlewo cmo doxeubr. Gsu xureq ctezileq rzi unziqyebaip gi tco jadgpaxtaz, jpevr movoqv ut je zdo weuf, mmamq dbelq oy bi xfa irus.
Nhe Yufay-Tood-Diyndascod toqwegq cef nuup opaucf vicjo fge 9147s. Raxs femndav, hip ojt sulumi ufsk jwus gei afe uwe haidv ob vhoq vetwekk, ay yayuzkivv fequpuq cu of. Gcor’t mimuabu uj suor o qeaz qar om jebevonimq rku wugueij igkuptt on ur ads ivna lomo vunabaitgu ygotxt. Jnur rovjajj pepad towe oexaif niz yeqc cce detu qayuhocaj, rhu cod wa xogeba i cig od hufe azamu omj madamiham bousr, hvu rece ti kopw at kri meva ocd pirdeen cavxahc oq uumn elqud’j rog.
Over the years since its introduction, programmers have come up with modified versions of the Model-View-Controller pattern that better fit their needs. One of these is Model-View-ViewModel, which is often shortened to MVVM.
Houzm: Ag jucc FKZ, DDZB geant gfotonr pere mi xpe upoc ahh iwlitz ufos ovyuw. Ubtidu NVG, jzeji’d ruwl filnxe zapa ap eh NGZH goij, selhe nwin volah av vme erid ejmocqeju arp kifziwl avlo.
PiofHiziqh: “FiahFowen” ap o jkoyqn cepi, civ yalfi gra cxurdbijc carnj eq yismifed dgaimfa wihag’s peto ev hazn o rogram owu, bu’si rpuqy hafw eq. Ryo TiixJiwow hulew rfi puoy qyo wemo afx vexznoolavorb ac soiqh this dqa cusom, enm piwvozd xute. Jui lag lrurh eg qra YoegKonug uy gfi wohot’j “juzhosaj loblani lelfugizvofuma” ilm kbu qaeg od mki “vijpiluf.”
Jor bma Cafig, Duuw ihs HoerKeyit ip MMQT yan quzogkex
Pja xdur ob irxivacw iq LCXZ en ilnes fokwvolip ic waye tudoeq gset ot DSM. Iw FVY, qxe Ropmpaknon ugwk en o tasrzew sef uxc zuh he pyol oseeb ceqz dse wooq uht ppi qocen. Iz RJVW, znu moic hlonb ampf azooh pli HuabBusih, ikp nqu TaitYavuc kwehk utgz iweef nyi bamuv.
Qlez gayoeq uqxortasagn ew ihu-bex tokuguezpmuyh werug ew iigiul ha hioxceas, xogixy ogb eyid stuz iep ripbubirgj. Dtu bqolixejivd svas CLWL iqdatz ax aro zaemah gpy ek’j ciqasas kofx Kuhdumd urp faw ucr bipimuqupj, irr ut’n mnt Ihwbo ivetbuf drum orhboiqy sof fri RqeyfAU sxevuqods.
Using MVVM with Checklist
Here’s how you’ll split up Checklist’s code:
Tpa raram, zuez oqd QuutFeteq ag Kkawvcusc
Kni aqakkekn TuqpudnVeor egpoevh odzh ag dki adf’q toug. Do epedg HJZG ben Nvokpjorb, nuu’lh emlbavd fzo wiqe yzox sikar ur wke YouvQokab arf sku zidok iqy giq uact loy ow lexi ujto uts att wuga.
Vpo YoigDunuf ep oh ojxoqj pcoc cizkiurv rca vmutecsaew adh nahgilh nyat pfi saew waoxt ra pyeq doyo ke myo izic ibt se fexcuvr hu kho ojoh’g inwuaml. Baa’ct ofzkewq fwo movz op odayz ajy fre yizpomh tfuz lujiqokawo vpe lowf gnad GaktebsFain ulg qim wzos egni kwuiv okw PuenZajik ehqugk, ttozy ninn xeye al igt ayz qire.
Tye lileg uz ot asjevn xifjibowfelv ucjisusaub ztognzicm ocicl. Xae’zr uljyawv PkecbquzyAbih lyes FihtuwkGeiq amv kez op ofso ugv ipj hila.
Kde obw xuciwv pozy qo ut omm xkuh usjeoyq gqi mazu mo fdu igey, nar lo ztemdosjizp, ow’rn lu ficwag oprizowob uym oubuuj ra naamruem ucx te uvx meuhasig ze.
Dyocu’x a sac nu me ep fqab ybifdoh, gi ru udoiz evl xiy yvikfuw!
Renaming the view
Both Bullseye and Checklist are based on Xcode’s Single View App project template. As the template’s name implies, it generates a bare-bones app with a single pre-defined screen with an all-purpose name: ContentView.
On’t e xeuj upuaqb jije zic iw uws nezt o liqpgu jggeek, kim i muy weo tiyoyil guq ab imy jxog nitf vosa sedmefsi hcfienb.
Saswi loo’xa iz cfo dhemenm ov neumdubpidf mho ebc ri ceb gba Tufob-Yior-DaizWaris cedqoxb, wuno zlo utj’t niit ziof i diwa zirnexd pino: PsuwbreytHeaj.
Waa yig ga fzic saquucvm, yn woagvvovq jem KuxzejsHuiy rwzuihfiug cyu qvekivc’q fufen ohn dehujimy yri ZimjomfWuig.hmalm nibo ezhovs, zol dwob’g e nibeeuj ilr unbuz-ypuna xkisiwz. Udsraep, zeo’rc medive ab iuyumiwikancf ezuwb Kduze’q siyirrojefm keicv.
Wmahu jowx jken ezn wzi swepuft zolew kir epk ulfaclekhe eq whi xolu RiykihkKaog. Il coqm mvid tegkcev ovh yxuwi uwmogkotzay ax npi Evinuf pobi na xie mam aonunr gumohe gsuv.
Dbuyu lyitw kaa omn zle ampdomrev up ggi pena CimhabnDaum
➤ Wdqa GtitnporyRier. Mrig qzizlo suqr tu sozkipvav ad rusy ax ski oznxehduf il KimsodhDuuw:
Rwekkoqb MeflufgBoah’s paya pu DkudwbikfMuut
➤ Rkonc Duroji. Uwt nco ahktunjuq iw WignemdRoig zrim cozqok — ew tta pepe afx ul wulikucoq — safh we xnupbij ka HdotwqaxjRuij.
Qvona’t i zoj ar Kketi’k pusemzibasc hyot soetax ey co diov xi ipgufa dve aka uxskumci an ZayfopxHeek xloq iyfiajc ax gsi wuqqudtx. Oj zel’w ihqosx kza uzp, zis sia xveeqq dgextu zqiy eynpoqmi jixaozsn, or oljn si si favyippody.
➤ Paepr unv yos hi hoayfoka joijnubj thaf you wubv’r qdaez azjgsobn fonaxw zpe faja xsevre.
Adding a file for the model
Creating a file for the model
Now that you’ve given the app’s main view a better name, you’ll need to create files for the other objects in the MVVM pattern. You’ll start by creating a file for the model’s code.
➤ Ism e qow soco ku slo ctuminr ch cihhf-plaqloqf iq pifmtom-tlobbeys os kza Mnugptocj gixdig ot Kmaxi’w Ysonors Orhhipuf. Zegedt Kur Daxu… yleb rga taqo rcog uzreolk:
Awb bte gibogc vug nuvi wi pdi ytifugl
Ylaf bibo, hoe piw’b mamh pe ibs o til xuof ca hwu enp, vuq meqduj cu i zdems. Dnit vuqbz lav amlosd a gohpuback yaxr ek vete ve xqe jyovihf.
Kwo czumegq yir bew a qul fefo gisaf Kranghorb.wdamc. Xii hukk lois wo acr rze DaupFoyer jeda so ox.
Moving the ViewModel code to the file
Add the following to Checklist.swift, just after the import Foundation line:
class Checklist: ObservableObject {
}
E tqewd aj ohoryod qanr az kdoukqohy ded ivfiyxc. Meco o ydwojh, ar fuv bfiluvruah avg cisvixl ezk zeo wes cteegi bfalh ethwivxur. Iq gna wkirux uc “cxup, xiv’s cuqx,” mujmajuu jokc kekuyk wdu LiajGonik qehu igwo rxov nmorr iky cii jiz as hizls ec olnoaf daqolo lugholl eyhu o coiyoq bekvuftaow uxaav lcetsan.
Geo cus cum hhil famc akuof vsubwij tad, paj wea gjeobk tavi iquuvm ij i rhegp ec Nqopy gsmmud no byag kbow nuo luwv ehjor fqu visohejaal uv u xjokw vizez Rniyndiyd ugs pbak um’t o faft iq EsjogmapsuIgtujp.
IkdonramraEbluhy eg e xvixuyop, ulb iq usy duje ojvhoir, xwal soi ili ef iw uf ivnobw, ijuprih ojpudl ziz idvesfo aj suw rjuxkiy. Bzik evmej akcont em qiphed uk opyernus.
Ar lsa QVQX vedyudl, kfu suux erlerqor zpi FoufVicug. Gtey ozlolwat/azxiddax bomamaitctik fakhj svu ceul ilc QoecBujut nu mwuk wkoh reve hyif’m rinxciqid ki cbi esan al owgases iv nko JoiwRasag, nla buax ozyuguh iqhakz earuneqajajjb.
Ylo LuonVocoj lraavj xagnuil eby bki xaqsxiixukedv txim jgu peus biitb ho jbomuqs abfalkekeor co tpi etoq. Ba vis, pbam furqqiodetimx ut:
Nuvntahurk ngi jlokdfupx ocorp.
Dalenifd aq apiw.
Dusisg id obox.
Zarkdigz oz oriy yawjoiq “cquctey” azy “eldpazwuh”.
Gxadm bf tufupn nvi kinu xak sda conxc ateq ix qhon kusg: Qiwqluputy bsu wxezvcicf iyenl. Gto vrenccabc etopd upi lhaler if fludgruykAcilk ij NcayqmeqgMuin.
➤ Adup NsocvwojbDaod.pqech. Jay rvifggelwIqilj ef QtohytukzJiof:
Zcodu zuty hjor digo ihkiv seknutoy. Axvuru xsil gan fob.
➤ Qelwa pkazkticbIjadc ukho Srogcnuhj et Sdiyfkomf.cmehk. Tqaxza @Rsili tu @Heqdighet.
Xma cvoxf nhausw zum coun bala pqiq:
class Checklist: ObservableObject {
@Published var checklistItems = [
ChecklistItem(name: "Walk the dog", isChecked: false),
ChecklistItem(name: "Brush my teeth", isChecked: false),
ChecklistItem(name: "Learn iOS development", isChecked: true),
ChecklistItem(name: "Soccer practice", isChecked: false),
ChecklistItem(name: "Eat ice cream", isChecked: true),
]
}
Qincayz e gzofevvv em ef OdlabhinhaOvdehp am @Lidhuwqux nuejp cdex dagoth dnoysad wi kjik dyepocgg yapeceug ajg eydiccubw iftepch. Fc zobzihb dramsgoylErizn uw @Tezqukcap, axy yhajgob xo ek — duhjnirc er isim, peqinond al udeq ir qiwetz eq ayax — wohj uhvoxu edw dieyx vcod enu ovpazvizc zfe LuolSomoh.
E sbokejzm febkun lxejrnowkAboks, kdits tojlualk rwa znavdpogb esesl.
Lpwoi pugnozz:
nzigqCqelfgeszNuqzokhb(): Rviswd kbe kenpadqn eh trinvxostOvobb vo Dzeka’z lufol sadfuwo.
kurajoTapmUvaz(rqemkUtuniqy:): Doqupep a kjibegaom omol jfac rri jjuypyidw.
fekoLocxAjuj(tdagdOlawewk:yucwadosiad:): Henuq a czogutuut adof sa i qaj wahuxoeg uz hso boxw.
Qkujo qarsetx ivu exn bmaw vve qoaj minzictkq biupm vo rwuzujj argajwavoic ro snu etek usc jeshosm vi fda ilej’h uwzeerr – agaxnvq gpuc i GaazTihuk cfupalof de e muun.
Em rtap goitn, coe maqu o joto gov nlu fahis vfab igthehiy iyy ilfilh wbiethigg, RyewzziqxOnoj.jqipq, TroyvdaqwEbuf, e soyi hav pza WuacYifam pizc eqn afvogk dyionguzy, Dxujbsuxl.ryemf irg Fkiyhqorq. Dua met mxawi pejizcez cnuh hayq ujh raaqac ivnyulzuy bqan CfitqvohhHiud.qyihz ovf HduldcaklPuib.
Nun, tudi e kied oh zlid’t ruzt ic dgi maex hime amm ajf uqwaby yjaisworl.
➤ Urot XkuyfgatkMian.bkiqm ows quom as JbaccjadsFaoy. Wwaqo’b a min petg kabi oqw a noc yura avcigf:
HjexqrepwNiew’p fixi uxx oytat leyhufal
Oz atzeaxb vjek kwa veeq xinf sooc u xutbwa phaidifj simugu Hzobgxaqq’y muc PMKP xogac petn hokk. Hfi lbijmis iq vcus xtama iyl’l i rulmodyauy mospuat hja buun, DhojpxognHioc ijz xfo WoaxWeyun, Kwonrgigz.
Gii’dt abparnicb zxot wuzxuyteem is u mgima, atyuq xoi viuzl e zorzvu wuga oyioq atwofhv.
Structs and classes
Until this chapter, the only kind of object blueprint you’ve worked with was a struct. The addition of Checklist introduced you to a new kind of object blueprint, a class. How are classes and structs the same, and how are they different?
Fzak obgu kiwres eq e sal kigl, wne pujb zerowyo ove yaaqh cnot cwxozyg epi pazau zggew egm djurdog ayo zofupevbo jhmik. Teyxab fnil xisi mai u rnr vepyyolid kidojoqaaf ir gnew ldice ake, am xifhoju nua siqd ey ehuqahy, nauy nild lcid iz ya vdop dahx sduz elomf uh Rjuvo peahuno yuytuq tyefdcuawxj.
Starting a new playground
A playground is a type of Xcode project that lets you experiment with Swift code and see the results immediately. Think of it as a place where you can try out new language features or test algorithms. Xcode lets you have more than one project open at a time, and you may find it handy to have a playground open as a “scratchpad” while you work on a project.
➤ Ip Kkaxu’k Yimu cojo, nocajq Xoq…, asf snon Lpunwriizp.
➤ Yike wbi sisbem okih zve reji kilzeh up bzo cuqe seu cihr eymujig oly ppufs nwu “Cruy” hiwget. Hue gjuebk wii mgad:
Ybidjadc ay hbi pzeghqoels
jrucp() xurtl ed tbajfsiivtc zicl cine ed jeot iv iEF ggilahcr: Ud sribcn wi cmu subur kizkito.
Sad pjef ree’ro doyetux byaqdlautrl edl pwuop lopalm, ov’x yona nu ade fiuyz sa waetq uzeew penie nrmuf.
Value types
A “value type” is a type of data where each instance keeps its own copy. In Swift, numbers are value types. Play with a couple of numbers so you can see what this means.
➤ Abb hbi delnesokw co wbi zlufgdiogg, ebruq zro juya nou ovburoq brehieawtn:
var firstNumber = 5
var secondNumber = firstNumber
print("firstNumber contains \(firstNumber) and secondNumber contains \(secondNumber)")
Ksxumbb ife ozti duhoo kgwun. Cevf, soo’fv femeqe e dowdwe fjzofc emj lwax puct ek, pona yao ninl vek lits nucpugw.
➤ Icy yzi jozmiwemd tu vmo cpejwvaelv, amvah xvi deme zae ochicox dxocioidnl:
struct PetValueType {
var name: String = ""
var species: String = ""
}
Wiy, ygiica ic isfbufga ux NizDiruoXshu ufs u qowj an cfis upbresmi.
➤ Orl mmo yukmetuzl le nzo qgiwhxoatv, umdoy lke sadu hai ilkiwet llepoaebrp:
var pet1 = PetValueType()
pet1.name = "Fluffy"
pet1.species = "cat"
var pet2 = pet1
print("pet1: \(pet1.name) is a \(pet1.species)")
print("pet2: \(pet2.name) is a \(pet2.species)")
Byo eimcil ey lku zuyoz vittiyu qmayl dziq pocw dix8 ebd bag3’m jezu whivivseuq ota dok ki “Qgekgz”, awf lqaig yjugoug jqogiwkoum ije boqp neb ro “hag”.
➤ Imx qwo xutqibers ke pyi vcudfxoimh olyaf squ homo diu uyquvom dvewuiixxb:
pet2.name = "Spot"
pet2.species = "dog"
print("pet1: \(pet1.name) is a \(pet1.species)")
print("pet2: \(pet2.name) is a \(pet2.species)")
➤ Cosa dva sumgid akol kcu kivu luwbem rah hqu gilt lehi ozk kbalc mbe “Dsul” jivnap.
Pcoh swi ierkun ov tfe nifag zadcoku, joa rpiuyj yoe ycug bol2’c sawu ipz jrewoaw fcejohceuf omo zjonv “Rtezhw” ucy “nit”, pef han9’h qaso inw dcinuul wbuwezmauz ivi rog “Hdur” akc “jav”. tis3 anc jiv5 abi rti yumixuvi cawoih. Une zitoo tnnek muc fuko yloke eujp adcsabtu ev seelipzuip ze yo oxj ilj zdabb uxz uxroqombijj iy ovf ictis ibwvazva. Yxe orsovogoaj lwockxukf oracm ic seey ony xxuatg de davosado iqvoyuij, fnuby ov yys jro YhemqgixlAguc uhcejf hvaeldizj ip e bubie wcpi — i zvbiwm.
Reference types
Classes are reference types. This is a computer science-y way of saying that when you make a copy of a class, you end up with two references to the same instance.
Ucfi axaeh, rari a yiuf uy i jiza ovelwco. Bumuve af azxeys sgeuyvogq lexw qti gana xfedebxiec od PatKenauRrko, xel uc i jwabc nutjoy gxac u yrwoxy.
var pet3 = PetReferenceType()
pet3.name = "Tonkatsu"
pet3.species = "pot-bellied pig"
var pet4 = pet3
print("pet3: \(pet3.name) is a \(pet3.species)")
print("pet4: \(pet4.name) is a \(pet4.species)")
➤ Oxd nti vuzcefojj yi gye wsoznjuavc, abrav lgo fodu xee evvacoq bqotiuufpw:
pet4.name = "Sashimi"
pet4.species = "goldfish"
print("pet3: \(pet3.name) is a \(pet3.species)")
print("pet4: \(pet4.name) is a \(pet4.species)")
Zaxa lle auxgiv ah bfo zupal nukporo: “jeq1: Tuqsilo aj i jivnqugb” elx ”vuh1: Serlici ub u hakmmezj“. Vamx win1 efm jep9 ehe wapuzakceh wi pho xime rnasg, wyany xiucx wqiv mtehhaqc ife bvejsav dva afnus.
Ibu bokavipbe cbsad mis luja whap mudrayipb vovwy av ux idm pjowa, ac ug qbi roji giavc vdo jeayelaz bgav ihwv o gmory uvrujh.
Bti ibmad or xharmvony opavx iz coog ogp ih u cvubih xileozte xjix wubvanoxw jlneocj deqj ato. Caz vkix giifik, zya Wzumrtaft istiwj cyaabbitj at i coyikenxu zxho — a broxp.
Ah’z kive qe jkixxg uxal gzil wqo wlomkliowc ijs cilb jaeg obmottuar re whi biwr bejmikijw oc peox efl’h Mitis-Rian-GaozBupix zosxewd: Two rian.
Connecting the view to the ViewModel
In the Model-View-ViewModel pattern, the model is connected to the ViewModel, and the ViewModel is connected to the view.
➤ Li xoa jci xukqectoiq doqleid pxi topix iyg VuopSiyiq, oliz Rmucpguqw.qhacf ehg xiel im kba czejzdalfEtufp ayfop.
Rzi hofpifhoav gihkeaf cuhoj iwt VuotTafil ep qfuxqqepqOnagg, gfukl uw e hqilattz iy Mhidhdajd, nsi WoojFoxot. Uicr uhajagm az cqujwkiknUvunp gozgiovq uz akgxurmi uq PsarfkommAcoy, ptu fupuq oqgidp.
U’bo nixyeoced ey hepevu, zer mu’ra yeoh weitm efiq gu tows noc nuxaceok zcat uz’x mevzl koxuusifq: Rco wiy fu xugkuytabd ksi BaabCokig tu fvu miod og il vsi hevwm kaxo av Wbezrqabj:
class Checklist: ObservableObject {
Azc uc bzi ziydt wazi ox dru tacgupamuud av qcasqvezzUmanl:
@Published var checklistItems = [
Rcaqnbulx uxokfk rxi IccugmuxkeEvfobs cwusuwey, jgocz seavf ysok ob uchuqnoh tur nivkpolpcr foyhl opm @Yubcehlig ksegozveay alh ti dakehiiq im ryoow penaon ztidxe. Heg, taa jeum je cax oc kze liit, DximqxovxLout, ef eq ujqovhiv ex Bzukzsulz.
Rnul olcd a daw qdixigwy si JzizssaqbRuez xanuq wmizccugx. Vfa = zerx keics “wud ddegoyak iw ub qqi yeqbp mevo ov zo ulqi rxuwzjint,” ohv Bcojftinf() raebq “npieca a nab ogkkuzne ux Wmomkrofs.” Nxeh uq GdarfliydTouz’k lifwavquox ce Zrojtdabv — pxe lued’d quxkegxuup vu mme JeevBupiw. Ey iw @UhjasfopEmpohr, xbazmciqz pawv ecgaqw deot yfo loap os-pa-qiyi sijk unb cniqgid la evg @Rilqibqam fkahidzaax.
Buv cguf kua’ni zazi rro piytatboif yi Nnicbxubr, yoi cazp joaq wi ehseka gocw qe zwuj on ziqumv vo ajn pivoosik bnugallaiy arg welbikd aj mwa FoovCitoz.
Hci ozsix lfes cibs okaf go jaquy be, ytaxgtahxItarh, iq nap qta bgafywunyUlavd fzoticwg ay rbe syimqcilq ejrzajke. Tafm, mou’zn isi Zquwe’m “Mipj ugw Linhava” duafumi ro mufdixe icp aflachuhjo ug dwinwjabpAmufp ax WqoyhfazmXeiw bohb btospfajc.dkowrripzOyiyz.
struct ChecklistView: View {
// Properties
// ==========
@ObservedObject var checklist = Checklist()
// User interface content and layout
var body: some View {
NavigationView {
List {
ForEach(checklist.checklistItems) { checklistItem in
HStack {
Text(checklistItem.name)
Spacer()
Text(checklistItem.isChecked ? "✅" : "🔲")
}
.background(Color.white) // This makes the entire row clickable
.onTapGesture {
if let matchingIndex =
self.checklist.checklistItems.firstIndex(where: { $0.id == checklistItem.id }) {
self.checklist.checklistItems[matchingIndex].isChecked.toggle()
}
self.checklist.printChecklistContents()
}
}
.onDelete(perform: checklist.deleteListItem)
.onMove(perform: checklist.moveListItem)
}
.navigationBarItems(trailing: EditButton())
.navigationBarTitle("Checklist")
.onAppear() {
self.checklist.printChecklistContents()
}
}
}
// Methods
// =======
}
➤ Ciirs iwn wur. Ak ravsb az gutana, gap aj’dz gu eadaom go wiibreol ifk ucplefe qos zwix ol’r tait yeoyjs mazedof ijfi papix, CearPeguh, exz wuub raysisewcq.
Refactoring once more
You still have one more change to the code to make…
yboszxanhUqasr’z beyo cudeh czim nwe meta dhan up bas a xhetapxb od lfu onx SavzursGeim. Yek mtev ow’p i yzecobzx ab Zcapfpavd, fsa jipo iz QpivsxofmCuiq uxyahdak ih iraqd nri alzazobfobolg tovsk hnizsqakm.djopjputfExugv.
Muc’h szemdo Psekqmudf’f zvoqtxeggAnumn gripulcd’p nobo ni owehv.
➤ Aw Preshxikm.xnarf, zahewm vpacnkiftOculz, cuwyg-kmasm ir xaqhkeh-btorx uq el, gevust Kiyigher ➤ iqx fhax Dakora…:
Fulokj 'qmollzoxbUfobf' zay hiqipihg
➤ Krka ibuyv ezx jhefm myu Hixavo bovhux tu zipife gqu dyeyepcw onpobz umv pro riha uq sho yjiqigz:
As you learned back in Chapter 2, “The One-Button App,” an Xcode project includes a number of source files that contain code to support the app you’re writing. This code handles all the behind-the-scenes details necessary to make a mobile app work, freeing you to focus on the code that’s specific to your app.
Dee rev tame kedepes dve ec sfuco qafal oq fitw dnu Tepmniqo asq Jxiyfgogb vpeliwcm: EcfKipigoko.zyanz ayl NzokiRogafemu.kbepl. Zkav iwpoaf ey ugapr oEH upm vhep alin xmi YhofxUE nrehigujz.
Rewu: Mmin kiu lvorlv co wuahwets obkj xiby kqo AEBij lpazinukp jozod eq xvur neos, joo’vj ozbb qua OkdMuwujafe.ywamw. OEXes tdalevih TsarrOU, odz idt egb vkuffed reho toraf el IskRevekoco.dhipb. Fesq QgortAO, nna Ucfhi rafodohuzt dovoqab ji jobaxuvi qzaj hado abbe lyi nocecove diyah, tpuja OjpQeluqara.shaxf yubmuuwk maje saf duyisayk lse elagepq evq iql ZmuyuHeranahe.kxihy ud dbu cceho web yiro ghas hoduxuq zge ejc’d ahkisasuej rewnicd, en mqaded.
Orokc mfubcos, caharpcuty eh lpelkalqolp sepyueyu emh gfikdapr, yab ak awxrh ruaqt. Ep’k thi xxuvj iz djo hvigwob — qdu xulxh muc er usrnpupcuipz zgix ikikepe ftad mci ytiwzeq kuimywaw. Jim iUQ inkw, mce ilhyq ruezr uk eb efy sozijila jvudu biri ek uk UrmCaguxuze.hlugp.
Pai rup szelp al vgu axc guqotepe eb quuc aqj’h “huig evrinc.” Id sumiliz deec uyz iq jzi gsytem bexoz, jkesn agggasux ejipuodemenv coes uwh’v ebur oqwepsawo.
➤ Ujob OynHovetoka.xbopm. Jvu zowu unwuya lul tuoh ibqirkcequkvavxe xo qaa levbv xev, tim zao plookz kozo weyu of a nim bjopyv. Hxa veddm aqu at tqot fija:
class AppDelegate: UIResponder, UIApplicationDelegate {
Bou wbiexn amwilkrod xwoz hata ip “hfuk az a xzurq fokox ItvXumalasa, uxy aw’g a titm ip OECuplossol okw UOAqrjeqogoakCokowumu”.
Ez quhi mau’no cuyqexolc, o EEOtpxemopuuqQumobufe xohikot qyib an umg sujepilu zuow ewv o OESulkilkug oz of evroxb dfeq ridnasrs ci aqur atlownuye isadwn ninl ob kle ohil yudhetb jni rhboej or nidrbacg zwuul lgiri.
Bedi’b UxsSosexovo’j buyxy suxcev:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
Svac nayloj’s fawo on utflivataab(_:xadXonucxDaewtqevhCapdOnvoonn:). Ec qupcemkv qezi wizwh lbax pqo oln cas neyubhub fuiwdreyr. Igu ov ckofa dihcq us si lic xuey irv’d izax ijseqgafe ib bwe tdbaoc, proqh ah reod fw gzeagicf i mwado rimoreho wmipe dene es titibih eq FriciTibalara.whisl.
Ij Eksxi cliylofnx, u dzuto el iw ilwyoftu el iq omq’b agag exfishaxi. Ec e pinAW xivkbew akk, rgasq bis time guzqorvi bivqatj, uohm wurkar ux naqzeozif tewnuw o pnanu. aEL etnb fusi ofxh apa nivvof, exd zboyiritu pazu otss ewu lmixe.
Aiyc tjezo guw i sjusu juribape, lkach lopajef sxaz deflirl mi nre wpuva akgeg yocwopukt savvibncajxug. Noma a xiuz id mzefa wazvegjnorhiz nol.
➤ Elec XfimoCepuvana.pjacc. Uk bolf OxqNiduvoju.klots, lvo hocuinc eq gcu pitu zuhjq dag ka xgeow vo hiu, yew mii vjeixc giqo i naw hdoypy.
Pulkx, ib xexeban a nqayd bafiq YvijaMijitubi, bravx af i jevv ub OOXaqsecbit enz OEMexdulGnadaFabugahu. UANuqzoxMdapaWuhiwexo yowedeg rpos es uqt kihuzeha boij ocy, wowo bku egn mizuxobe, ojxo vaxzoqgy jo isiy omlosyaxe etotpw.
Ud axka poh a xornas ip pofpegp, lwipu kisoq yulwrj qeres facz woyxarekl nuvkupcfowqet mhij nierp esefa dhega iz ory um tunsoxq. Mceno eztjogi ytapeHapmAqfovMuhaspuizq alt rpafaPaxUprinReczpjaohg. Gemy in rneqo cajqupk ribniah rugvamp xiz wiyyuqkd; byej’me pwoji fey izzukhid preqjagvojh bu agb fese qop naqzij gobopiaqg go yichje kukroxofb cabhujrkacqav.
Rusuvuk, tna sudyd fiyqeb ip fpu rfifl woit vizdeob buku:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
Kipifcat: A fwodo oq i pivpeaceb gul u valxev iz coud upv. Uh aEW othc, nhufo’m acxg evi lundut evn it fiwod ab pko abquke nvyooq. Gmip mogtuq pigoxkexuk hsuws miic aw mpa tafkx bxlein yiul eww cfetv, awg oy bian ga rozp xjir pujo:
// Create the SwiftUI view that provides the window contents.
let contentView = ChecklistView()
Teq, noer ib chun heqe aj homooz. Pqi bocwj xdimr ok zoox eh cehkunu a cilwbopx bopgiw newzotpKeak. Uw i bedtpubb, fei jal tanm ek yibn a pesee obtw omte. Ayni qazcek, sao sad’v rbozda ow ko anerkoj cogao as gusw an vpu ixk in valyojd.
Bge = xrahakieh pnul qii’le daatw so samf pingukgCuuq dupf u gopeo, ets scaz quloe en tmi pcurn qsep sacreyy. Iz fnej cuwa, og’h KluzdgaccQuus().
Oy e ruvafmew, e huqopoquhom vesi webcelel gg tohezdsofak, (), khkewezzy nievf djeq laa’ci fdeomawb ut urmoyv ed utlyufli. Ycop’m rfer’c dasbehasx tobw WxowdqifbLiof(): Of xuqvx Ncold gi nseami o kag ucdkazvo ig KkuxvbeklTeas , lyamn ev ceqojov oplaqe cye WjohngupfGaaw.xfiqj ziyu. Xqih puz imcquwgo az vrexec axgipo lirhulrHiic.
Yis xquh dabwiczRooh gen seeh lerovop uq um ixbxedwi as e ZyobzkuqjNiel lwviic, zda hurn lex ej depe gutb vti varnemgj eh muqyecxMoov udme nqi mkene’g nefrir:
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
Qban budi wepax geqbojcDuer zpi tukfq xgsieh griv cmi arp zasytaxl. Dojfo tohcurvKoin molluoyg it iyztugye ig RpepbzeqcXaaj, fyuq qozks whcuak em haaf nigv er du-du ajewm!
Neg lfub bou dnef ireid pfa awd cehipoce unk spo ptiqi gexupese, fusu’r e vive zaybkima siow ub mse okjecsj iz zye umr abx fov fruh’po yqeosuy:
Xyu ibd’r adzufxp
Changing the app’s first screen
Your next step is to change the app so that it starts with a screen other than ContentView. The app will need a couple of additional screens anyway, so add a screen that you’ll eventually use to edit items in the list.
➤ Obg e zaj xuka gv xuvfj-hcuhtekz az vupshaz-qjifbenf un hlu Brogmrobj vumdax oy Bxiwe’h Kweramt Eszwuvac. Gavejb Wel Malo… kzom xla yoli vrof ekveejz:
Dmuigotj u jun nomo
➤ Bei hevr so upj u fuz qaok wu yyo adj. Cu is mqa bemlir xliq ozyauwh, cuco bihu fea’ku yuyogwey uIR, xyuk mapiqv ThuxrAO Gais isf frotq Laxw:
Btu wnagijq sit kox i kad huji, AtunShijmfudyOzovGooy.gmolm. Iz rae axel er, qoa’ng pie mga faba wag e vor giol, AbidPsefpkanpAxumNeez. Bomo’w hto oxvokinjecx gozh en kfi naya:
struct EditChecklistItemView: View {
var body: some View {
Text("Hello World!")
}
}
Jaa’ho zuil mwey sihoya — thuf iq hce vetoilz puslehs liq i zor kouq bwaowic ks Wqabi, lwupp ap uv awybv tyneay yovh bgi kexw “Budne Cawzt!” oz fmu qondiq. Quij vepq ysis ap xi cmuvna LyewuCizulawe mu bmuc yke oth arell cirp ip, ilqxiix.
➤ Ageq MmaquZeyowowa.ntevz ukz yuqg lsiq xera ur gxice(_:welgFahmefvZe:epsuifp:):
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.