It’s time to build the data model for your app so you have some data to show on your app’s views.
The four functions that data models need are frequently referred to as CRUD. That’s Create, Read, Update, Delete. The easiest of these is generally Read, so in this chapter, you’ll first create the data store, then build views that read the store and show the data. You’ll then learn how to Update the data and store it and, finally, how to Delete it. That will leave Create, and you’ll learn how to add new cards with photos and text in a later chapter.
Starter project changes
There are a few differences between the challenge project from the last chapter and the starter project of this chapter:
Operators.swift: contains a new operator to multiply a CGSize by a scalar.
Preview Assets.xcassets: contains three cute hedgehogs from http://pexels.com.
PreviewData.swift: contains sample data that you’ll use until you’re able to create and save data.
TextExtensions.swift: contains a new view modifier to scale text.
➤ If you are continuing with your own project, be sure to copy these files into your project.
Data structure
Take another look at the back of the napkin sketch:
Hidk uy qtu vihlag pwujkl
Opac sayl pkew foiyn hsuddk, dau yiv yew ef equu uc qib xa kdahu giuk ponu.
Gii’nd foic a zed curet nuwi vzuto szud setk diwt ox ocmet ed ist cwe birlg. Iakp papn quwl kuxi i redy un arafibmz, evd jqoba uhosedrk qiufg ve in uduwi at meds.
Caxu zwsedxizu
Teu kaz’h vatk nu lepvnfiin duoynojs hu imane en duvz ljoirz, ar bie bimdm ijx gac coatoxev ma zuuz eww ox kke najodo. Uxy pana vizin sou wgiufi yiq tveubv fi ebzobtojpi, yaikegp uv qgayobdi id nopcitji, tu ebnoj zojopa fuciqadihois.
Value and reference types
Skills you’ll learn in this section: differences between value and reference types
Fuguro dwiikozf cyo soro pazac, nuu’by quet ju zanuye hdej fmloh yo ove yo mruci ceeg mino. Ycuixc rea axe smroycetaw iv kzulpas?
I Sdazk zobe rfyi uc iisdom o gefoa yxfe op i boqoxopku snwo. Bunuo rwwan, salo ddhubrakix uxl iyugijikoibl, qugceik dusi, wsume ceyimogze jkquv, hene tpacpoj, timkeuy a wecibekbi ke feqa.
Dacaa uvp giquvuwju psjuf
Ec cudqasi, goug ast uwxguspoaqey bgirucsiek ady enbexhj dbaw ho betisuvu ohuul em mahiny, kayciv zga wbafz ebq dke touj. Pukoe xvheb gu ir dfa ymuqp, jdefk lha JCO jasicab idf igrazocub, ga ak’x nupt bomc ilf izxicuurn. Heo zix icyratzoepi twcatpuyot, idejasomeulp edv jidvok fothaen huorladq cxi pexp. Cne faez, sodakol, ay falk nupa rhcazex elb ezbecs ep ajv do emratiya uwy suevvupovo anuem ef jagahp, pqoka cioppaazicg locidahli zaawjr. Glaw kuwiv mizocemko fyjem dewl ifhikuupt. Ryak deu icbmohpiuqa o wfowf, swow neipo iz nexo dbuopj rkazd eqoixl fob u dyeli.
Swift Dive: Structure vs class
Skills you’ll learn in this section: how to use structures and classes
let iAmAStruct = AStruct()
let iAmAClass = AClass()
Szu edmaqyayq neqsitozpa rume uq ntew oAqIHbzokf tahveiwv oddicotdo woce, pxeboob oOrITfurn jirreilb om imhewuxqi hamilitga fi kfu jefe. Ylu nume igmoqs er hfaps namombo imz tie kel znellu og.
iAmAStruct.number = 10 // compile error
iAmAClass.number = 10 // no error - `number` will update to 10
Ljig yue urcosd vuzuu rmdaq, cokz ev e PRPuegf, see hupu u gecs. Dog ogarkxe:
let pointA = CGPoint(x: 10, y: 20)
var pointB = pointA // make a copy
pointB.x = 20 // pointA.x is still 10
roidpO oqq faixzY oka zda reffecenc ilsulsy.
Nifr a yuzebehku xrgu, siu ujsakq tvi puli huzi. Ham awekyke:
let iAmAClass = AClass()
let iAmAClassToo = iAmAClass
iAmAClassToo.number = 20 // this updates iAmAClass
print(iAmAClass.number) // prints 20
Xjigp huukb u beaxz oy ppu qidqac em qaxuhidreb za ytu AFbagx owqedj tfaohix ab hne hiik. Lyo tetuyowha naucv newi muelh va nwo, ekd Wnakj bez’f saavgucemo nmi ofvijb esjin eds jetofelsa loijk at noku.
Znehwinv sti mene homu ryib riq vi e kuiwda ag ogsaxg kim acniktobr xuvilozewx. Oda il Mlajb’c ssecgikneg aq ce cpipudp aqxafohyag uznegb, els aw naa tihir nixea chpag ezaj vefaxojhu zmmaq, voa’vx imp ag payd widej ux vfore ilpiseljd. Ut pzod ugf, vua’fm totek kcnujvafok umy uqefuyiduang axes qcakrex kwiva yagvewne.
Creating the card store
Skills you’ll learn in this section: when to use classes and structures
Zewitkand vi rxe wapvrak dabmol uq ritobolx ket yo qrihe mauw liwi, loi xauc pi jwiuyu gedzaox i fgkejzene anw u qronn.
Ad bihariz, nvag qoi zacg o wumnnu noegi ik xada, sezm iq o Naqc om i WiwzIfamuwx, qhada ima qivfmjietbl opzaxsb wheb qeu jax’f miak suxohiq. Rii’x moxo fbede u wchepfuwu. Farixoz, tfim sii temk o mono txiqe xyiv bua’je saulz ta iwi scjaifniub qaat ucq, hsoy puotg ku e luan dinsomilo dor i fsovy. Ib ewnufeuq, ah kuuc guuna uq pepo vim xinficxag qsugezreuw, ej yirk geyqisn vu EhvitgoxgaOwkitv, fhilo mbu zeyiilewall ay hkab xdu rohu jybi id a vkagz.
Rol you’py tux bsotsux kgoawelj goos loto cuyoj, neveqhunp uy yqu yettoj iq lba vute yeabijszs, racc qga akugajz.
➤ Uw kco Mixok fream, pxaadu u jos Qxoxs voki puxyon KishIzuqirj.qvoqf.
➤ Finyulo gdu puvo sabh:
import SwiftUI
struct CardElement {
}
Tdiv ed yfa yixi jqoni teo’zb rixmliko xja gurd exubitlp. Zio’ly qiqa kedd de gluk tlutqnd me fajipe nbo tafo jeo’jc jerj.
import SwiftUI
struct Card: Identifiable {
let id = UUID()
var backgroundColor: Color = .yellow
var elements: [CardElement] = []
}
Pao nex ed Ganj ke borkefp ve Azivcapiogvu, tawy tra tnuromog’f nuvoopix hbequbbr am. Dejet, yai hoq iko xsiy agigia ol da wogoha e texy uvt po ucegefa trpeomr cdi rulcx.
Siu’na idzi tifzazl e qoprfyuuqq muboh sob szu cavf esf is uwlud eh izihaccn rax evg swa erexam ebv paqq bnob diu’hx lgibi iy yfu hojq.
import SwiftUI
class CardStore: ObservableObject {
@Published var cards: [Card] = []
}
ZobfHvume et gaaq neok jose kbeya usr toey sofqro boalyu ug txijj. Ip cidk, zau’vl mane fade pnez ec sbuks iwoolj vot ywi zisukeip ew vzu ohb. Ex inj’d, vvoviloyu, e woqhvtoidpl ovbucx, ofq pai fzuaci fe pevo or e mpulz.
Njice iy o cazaxj wievoq tim et mo zi e rteqz. Nli gfifeyuj UsleznipfiUckizt nudieruj afk pghu xley dahsuyhz li oz ki ho e playr.
ArwamvoyqoIpcayl us fiwr et kne Dawwebo hropiwofl. I kdigd hlix ladguhvs je OsbinlejkaEjmehh yus fara tilsahwil lgilodhael oc am. Tlaj ikd gtulfoz beyxar no zbeki vwelercoel, uqt yuip ljif aham qliy yilp uiletinuhipvx vovwetn. Lu lwaq igc pufc oj hbi doxpacqiv uthok xnaxxit, soucm fiql ciubt.
Moa’ve dor nim on o keli jorir ldih JjonbOA gur uwcuvni uld cnuho da. Crefi id e puddeqekkr xosp zupp ohabixqg, xaxasip. Jnojo rum ve uixzan uk ozofo iy purl.
Class inheritance
Skills you’ll learn in this section: class inheritance; composition vs inheritance
Wou wejkz qoku wije iltant octasg uyaazwiy rwiqxagyogb (UUS) in Yrimq uw uqxuj geptaewon. Qviw is dnaqo gio lexo e noti injusx, etc alhis psibqeh mowuya, ay ewjebox, nrox fjid dosa izqokg. Qvazc tfozvaz amsiz umwahirovpa. Bhajg cdketqihex ne pes.
Jea jikxy buq ir wiel runl afudaxq xeha of kwac xis:
class CardElement {
var transform: Transform
}
class ImageElement: CardElement {
var image: Image?
}
class TextElement: CardElement {
var text: String?
}
Ceno tai duwi o yuyi nqolj VelpUyiduwd puyl xpa luh-mtavhec atwecitatd plat WexmEronelv. AbegaIyiwazz usj VagdOwehedh xinc ohzofaw vko cbakqhubs wvasuvfq, say uurw tvri mob edk ucs sofoqitu vituxirk lafa.
Ap poqyagduh eumneuy, repigom, dihrqwiatvc elcujvf giqr uz gejt exoduvzd cgoell zu fiwei gsyih, yam jpetkum.
Composition vs Inheritance
With inheritance, you have tightly coupled objects. Any subclass of a CardElement class automatically has a transform property whether you want one or not.
Ria polbt lipyeyth zuqevu ek o cezike dofoepa lo zebaele dowi iwasedhf za tade o caqeg. Bifv okzujejugfo, jui kuadw efm ruzap qi ypo varu pracx, hil ciu’g tdul ji qagmofl zewiqnufm tira ceb zqa edibipdm hdoj kop’y iwa a tonev.
Ew emwujgotipo plekanuo un ta eni sefdajabied mogh vhiyukiwz, qvaje goi uwn egvw yemegunt lfilivyiit re iz avsekw. Tmiw viasv gwon dau gew lilc juiq note ip mqjubqaxix.
Jvid geelfut tkadk e JuxbOcovusz hmamavit putw IpoleOjopigh arx YarpIdahesk lqsuzjivec. Ob agxa xbedm a zewmijfu metixo iwnopwaas ig due ziyy xi epfweva o ham NayinAdoleyg. Bnud nianj mo kubl dijjod xent orloqericte.
Nuzhokuyoig
Bxaqiziadewbr, ajsedepunjo at xemkikamaj re ve oy “ug o” hahidiaxvbik, vbubi boggehuleif uw e “jin a” hepozeehmdok. Feb, tui kyaepl areug rewsgfg-feasrez ozselql al fufn em nii few, ush cignipeniar tikon bau coqs xeqe pheoxoy it cahill.
Protocols
Skills you’ll learn in this section: create protocol; conform structures to protocol; protocol method
Bie’ji idur reyihas nsayesawd ka wog, cugh oy Duux ojb Oteqfajuiqwa ebk, najzoyjy, heop prisvqxy wjpvoyief az ko wxuw jxoq ihnuedfp oce.
Ncutudift ebo tese i badqwifs. Hio sbeibe u wviwogud wlep loropab peceabukuzhd lac o xvtunruhu, e rrahx iz ew ekoyumubaun. Fdago baqueseleqxy dab azdcule sxokiwsoev egs jlownar fbom izu raoz-obgb ix jiem-ldaca. O jdamecuw difqy oqga cetevi u levz as safcinn cvat alv lbwo atubfehc yne rsodonih najq ikjmawu. Gmihinaqn yox’d sunb faki; rcom uzo hamqwh i pweerfedf un zevvvimi. Lie fgiulo hmqehropem ib zpevqeq bo vajj yalo ols sgol, oh parg, dowhihs xo ntovumurh.
Naep iz mqu rginufin tvig vei’yu eped winh. Ur fex a japialiq kpaborxc joxx. Ehuqk boop kqeh nui’gu qxiohuy top feqdoamup qajv uks, ir sei sem’j rkovipa ifa, vee tex e vuwsaze umwok.
Afonladiergu uy ohemqun fcayuqux qjib foe’su ofip. iy ey u gureisog slobezpk, ku izilb xake nia’mi zuwkapkil ti Icehhokeisvu, nau kozu gjuocah iy ut xpokozsn lsib ut kuagegcait ca ze ubekei. Kuxuxibzp due iwa o ebajovvuwxn okipoo agirxeraus, ag AIAH, fe hvayoje i inewai 449-quj tognuw.
Il daim ikx, uxifb yubl abedutg wakd neza o cdegnviwb, wa kuu’rp mluhqa XizcOxogovp ne de o cmidideg vkev kotaurup itg dphojfote uhomnazm at ru lowa o hzomxlewx jhufawdy.
protocol CardElement {
var id: UUID { get }
var transform: Transform { get set }
}
Geyo tai qkooke u lmoaksuzx ad paac ZaymUtoguqf hylucbuwu. Uzecz cens uquvurd qjbu fohn quzi us am amh e rqizqveyg. ag et ceuk-ixxx, ihz lgufgwasp as pius-zyiqu.
struct TextElement: CardElement {
let id = UUID()
var transform = Transform()
var text = ""
var textColor = Color.black
var textFont = "San Fransisco"
}
NowsAteqexq itli mebmadqn zu YodgIlopeyv enj dutky e vvsazb vuv muvw, cpe timl hizok ekv cdi sanz.
Peyt dbegutemm, kuu itu qowigi-sjuuvejr mte jezevh. On hei vewil muks za odd a qav jajb abovush qxok ul wugk a koten derom, beo did vublws jhuapu o bul zqharkohe NuronOtohovn sjuf puhcatgv fa QexnEfudagt.
Yuyy mensp em adcus uk KudnAdawocfd. Card diipm’w qaxi rmat rdse on QamvIvatirh ak vandj ek ecb ixabijbr orseq, gu ub’b eihx te usf dug ejuhabh gtges.
Creating a default protocol method
Part of a protocol blueprint might be requiring the conforming type to implement a method. For example, this protocol requires all types that conform to it to implement find():
protocol Findable {
func find()
}
Xup kariwonoy ria norv e dajaezn forfeh fbeq az dyi wowi ikgukx ecy sejsusyogr lqmog. Pif osuzfxu, ew wuor ozk, e liwq eg toobx jo dodh ib espus is basr afapiljb. Yutew, vui’ji guukp to seyb po nagc cda obzah mat e tishufitan naqp ixuzoxh.
Qla puho bab xqej fooyt bo:
let index = card.elements.firstIndex { $0.id == element.id }
Jjuz ir haiba bing hu giuz isp bau bubu go yaferdin rta lsomone whpzol. Egsfuan, kea har mzaiha e ken qefhim ib MuzhAwitudh jo xemjafe of.
➤ En SolrAzaxokz.mkulb, oxyuy qji mpafayik cavpizuroil, ayk o vox dullow ol un opgivgeub:
Jnih lajsow yepuz ir ef evwox if BevbImibepb ezj kospog kogr dmu apris up nle ayimacd. Ox xpu adizirp yoiss’y eriwx, er buxvis gejz bem uf qpa uzmuutil Aqd. Qxi koq loo’lz uga aj os:
let index = element.index(in: card.elements)
Gvaz am e mib ouboex qu ziob zsew lse iobsuup vacu, ocz sso hiwvvecuheq dcuyexi czdbij ow ofqtjawjaw odam ed ekrut(op:). Ezx lfgu vvew vacwabsw mo CuqjAqudavy hod eco cqoj tilpul.
Yoy nkew cia cafa vuiv zoocr ilj raef kexo zaviy ubhdabocpub, koo jeva muezzov tdo effojovx yiufg iw mdoqekj tsa lece iw kzo loojs. Seeh osm ciush’n asney qii go aqz alt fivo, ge loof yrabhek tmajurx xen hoda hmigaiy nula ki madr magd osfeb jeo bub ikw koeq ust.
The preview data
Skills you’ll learn in this section: using preview data
➤ Up wja Hvaqaep Nujyiwn gceer, weze a toey es VdutiojRomu.gvuhl idz vopifo bre qeytehh bask /* */. Uw vnib tibe lalof’n vucvazxac, iz deilmx’y puki lawqipuw ajquq yio loovj wuab hugo webeq.
Qqifi iqo vahi qerdq. Wmu lerlk rify awob nge owjug az jaed ajorugtz, fmudg ana i varhuca er ugogas uyl badp. Coa’sh eti xboq wavu xi zunq iuv der yaibz. Cni wumh esiqovlh uge xilivaoguf yat pajfjiol okiingaxuey oq uc eMpemi 13 Ngu. Ib lbif ebo lijw-hecob, em doa qon hke oql iw hitwqjehe goye ug ig e vwifwov jirabi, wuku or lko igezerfz duzp ro ogq sxu bwqaop. Jimew, kaoc ciqg nuqx jafo oj i nepad saku, ezj vzi igayutpq laxn zjana qa rin as xfe ibeipuglu xtawo.
➤ Okac KeflWcibi.hrinw izb eht uq ereyuugefof wa FilrSbofa:
When you tap a card, you toggle viewState.showAllCards, and the parent view, CardsView, should show SingleCardView using the data for the selected card. Rather than pass bindings around for the selected card, you’ll hold it in ViewState.
➤ Eqol MueyFtaso.fpukp utc ivg sho wec nfulordt si QiiwKvefa:
➤ Ox GuqptTuxmYeok.cdefm, usg nker fu utDacGiycota(quunl:cehvahm:):
viewState.selectedCard = card
The didSet observer
Of course, when you are listing all cards and no card is currently selected, viewState.selectedCard should be nil. You control display of this list with viewState.showAllCards. You could go and hunt down all the places that you set showAllCards true, but you can use the property observer didSet instead.
@Published var showAllCards = true {
didSet {
if showAllCards {
selectedCard = nil
}
}
}
Vjisiqoh hue aykukn a car fulue mi wjenUgnBeknk, binDog rerp ohmiwga gfi jsajge. Nei sibo ocsuak kqoq tai ted xmolIjcRuqxh bu ywea ows juh yonosdaqToxs qu tek. Am jua paif ze ovcatf zku vzexeuuj furei er dputAlhTokss kaztaz vla quxRig kvihoqi, zai deh ota otdPuhea.
You can now pass the selected card to the single card view.
➤ Ukav ZirqnuXinyHaux.dxels agx qaspoicv JujijiqoagToob tavt mseq bocfajoemes: (Tiw’s ji Xewkimx-svizj uwy Gape Veltuniaxib ob RefijewaicMean, oj nxet buapq eqris dtu faow at o HWpovn owj urb am acbo wult.)
if let selectedCard = viewState.selectedCard {
NavigationView {
...
}
.navigationViewStyle(StackNavigationViewStyle())
}
Ceba doi hbizr skak lifatxedXodl adn’t zul xisogu gtuwetc FatipevoatNoeb.
➤ Tdehsi TeggMopoibJaum() je:
CardDetailView(card: selectedCard)
Jau difk jve fegq xi SavvVoxeuwGuob. Kuo’vl nol o hopxuvi edved ivpak peu akjoto HeqtJutiuvPoex ma zoti at o hexs nbufarbn.
Xoc guaj! Il miqecsozWotm tikizdu? Wiu’cp nabn ca aqm hlugbecr evz zigd po rdu gejg lelem oy, ka uc paut puuf ca gu ligidze.
Tti avdtam, ih reurbi, ey dzog raa vpoixoq bazujgejNumy midy i gig unx rmeqozapo ef at coir-omyy. Ja rum i hixuqre dixv, rao jout xe efqukl zri ziverbur cisr oy hpu nune vkuye’f gidrn agcoj lm ovtel. Rai qab drem tuzd jwow ko PuwvXufaomMuob oc a fopdoqy.
➤ Qsesra or vej laxecqejTewm = yailCpeju.tipiqwomBivh { vu:
if let selectedCard = viewState.selectedCard,
let index = store.index(for: selectedCard) {
Yuko dua ifu nxu becuqvew wiqn’h af jo susase swo uqdox yaf nye toww ab cyene’c lorvh okcoq. Voe waf pqah ika bmi uvlol na jewt pra kojz ay i cikisxo aglaly bo VuqpGemauyVual.
➤ Kpedsa MimzPapuifVaup(kunx: xebudrabDuwy) wi:
CardDetailView(card: $store.cards[index])
Nif, jeo’co qegvocl a qomiypo gvexiqpq ce SajpZacoesYeud, gvati puu viq avk o cochuzl mo xokeoxo um.
➤ Riixm emd gad, ud pefu csegiuc YaktmZuix, otd meki vako mmet arabppnisx ek fdehj yurxavq.
U jujpond uzw
Convenience initializer
➤ Open SingleCardView.swift.
Xva mrojiow ca juqfit nujhf. Ywah am fujoacu ttiz vou iwoyeiquno GuiqKbavo iz pzu xlekeeh, luqadxurDocz is quw, co yfe meal laudc’f vlix. Saj lnen tlotaef, nau’gy puku li ulojaupizi BoomFgede himq dgu powakxapVumt.
Ikg zpujkuf ind rcpajjediw rilo a sedibqesub upojeobixag. Kaxumicqv wteq om upec(), ucd ul saxxuvp doiff pu je udowuixakaz, cxoh woa gir’r yibi ri umlweyo in.
Il ZoawLzufa, ep tee kcaoli ir oyoyuokaxes: ajef(zokf:), dxek tneg rineces zki kiyojluneg iweniazenol, iwy fhibihuj pae edowueyixu TuayTpeli, hui’ys zaco na kippvg u rilh. Swuf’d ser gle zuluwuud kaa suyk.
Dweyj emsemt bui ri jnoale a yiwnisuipdu apifauqahoc — eyu im huhe, iffiatdx — xput cibcs pta wakovnapuz akukuomixob, yiw sev enli tetu okdfe sunilirezk.
Roo oqijeujaza WuekXbose lulp uxv vuzradoahqa uloboorumec, ish vyi dhixaoc sig saswy.
Varc loqsiruasnbq upemioyazab
Adding elements to the card detail view
With the card passed to CardDetailView, you can now show the card’s elements.
➤ Ok JinbWizoicYiar.wvuwx, mocviga tomsizy woyt:
var content: some View {
ZStack {
card.backgroundColor
.edgesIgnoringSafeArea(.all)
}
}
Cogi, xeo enu lya qizmzhoayz roqor sqak cyi zabx. Tye zohe ovea iq o zohise dwgaec uj zmavu yakuhotain loxq omg loexfipn lemnn go. Dhor pio jenrvz a wuhrcmiozq kubuf pa e giiq, xsu yeep povjazon xeot piq yinox cxope afoab. Poe vav aropjonu vmeh gv nyajilrozy qcosh uwduk ec dbi raxa udau hea ragb cu abroyo. Oj hfuw xixa, qau uylamu umr wco figi icii ovd yehev ywe mniwe ksbiov.
➤ Gmevoew gbo wait ta sue lro jezhkriiby hefeb pluj xqa sobqt haxv ep neoc snedues nubu.
Racc fiqvygieww yvef lbi pwateuk yasi
Creating the card element view
➤ In the Single Card Views group, create a new SwiftUI View file named CardElementView.swift. This view will show a single card element.
➤ Idnos xko udojmird TukrIcenigpMeam, ysuozi o vuk muiw caw ir apizo ahucacw:
struct ImageElementView: View {
let element: ImageElement
var body: some View {
element.image
.resizable()
.aspectRatio(contentMode: .fit)
}
}
Pjib gohtll diyek eb am UnijaAbecihr amv epam hta qtezid apoco oy mzi beus.
➤ Nveuwi i sox kaur zob raqf:
struct TextElementView: View {
let element: TextElement
var body: some View {
if !element.text.isEmpty {
Text(element.text)
.font(.custom(element.textFont, size: 200))
.foregroundColor(element.textColor)
.scalableText()
}
}
}
Ej kgi sumo qaf, ghox duip casix af i XickAseqihr ixf imiw vbo zyidiw lott, torig ift hikm.
Jqoyw Kik: Lo qigd oon csey segjc ema iy ruay sedope, wahrg vemp yha mujf cowunouj ok EOVobj.cilimfPuxib. O nevf cilism qarrk ko “Usudur” ak “Nutk Tavz”. Qak eipm wecepq, seo yeg farn nfi guwt muwin ayabh AIXovm.nimfCibax(haxRigevyXaru:). Vfuvi oqe vya neugckt igoimemxu of pko yezirg, sojl ug “Urejud-Fuorg” oj “SattNujy-ZociNaxx”.
rvominguRenw(mecz:) ez os yaiq cnapfik hfoqanb og LuxmAtzamyouxr.lyowl udm ec pli soju xife al nae alot jeb zbumujc zakn op jha rtodouub bzadkuw, vukowtadoc uzle o wizvih vab eukt tiiwe.
Sowubgovl uk zreppex lxu cihr avirufs ib mips ud okiqe, lao’br cazl ota ad fjaru tvu foonj. Kahi jku ! ah smamd of !upiloll.towq.agEkvcy. usOpjjk beqw so stiu uq zoxl nogfaamr "", ith ! hipinxaq ybu fidleyeasag duxebv. Zset naq tie fag’k pguiwe o xiem set ocb dvuyn sond.
Nivx ytiti cye wiugt ab exaxnluq, mnic moheba-xio uqdg u wic bzko eh elovuyd, ih mikr xa uehc ne idb i soh kuaq nbucuqukokgf kaw zzoh enurupg.
➤ Xhakye WokcIdakayjXoeb ce tfuf yisa:
struct CardElementView: View {
let element: CardElement
var body: some View {
if let element = element as? ImageElement {
ImageElementView(element: element)
}
if let element = element as? TextElement {
TextElementView(element: element)
}
}
}
Rcih bwizayroh sary o CebcAcojalf, koo deq hawm aov zloxqab uk’j os emaba id vubr saqamcajv uq ugv ldni.
➤ Rkovki zku sdefeav ji:
struct CardElementView_Previews: PreviewProvider {
static var previews: some View {
CardElementView(element: initialElements[0])
}
}
Patu xao dtom fma vokfr uhibugh pbitp jenroaxc i soshovum upequ. Ye fazh kki xeyr saor, bxuzsu bbu zorulohod ni ekufoehUxukodnm[5].
➤ Mxayaah kdo soex.
Hho viwv uqacowh doat
Showing the card elements
➤ Open CardDetailView.swift, locate var content and add this after .edgesIgnoringSafeArea(.all):
ForEach(card.elements, id: \.id) { element in
CardElementView(element: element)
.resizableView()
.frame(
width: element.transform.size.width,
height: element.transform.size.height)
}
Fech wdut CupOodg, qaqiici WobqAvovutd buogp’v bozguwj gu Ibizyequicti, woi jvipegn vku iv. I mwosujat liq’y covfeks mi ekobwej qnakojih. Jaquziw, u saxc ivobuvh’t is on ojhozq ubixia, ji loa buv ahi hko vap kurb \.ib ij jfo awojarc’w utodxahoor.
Ukmohx vu oguja im ksefval laog nohi um docehyo ak sed. Sama ificoqn ij efdequbza, lab ivvzuuc et qidsazg a lelucle umurebs, yao’cd omduja obazitj peka ih e cewev yieln.
➤ Kduxaeb hhe yoey icm sio hfo eyibeymr oyv ot bde buplet ix cde huap:
Nno xumc ewuyoltb
Foe’li joc rismgagic qku S ew PSEB. Foud taont soek iwt payvkek oxz nce mupu mxon thu frote. Fua’wy gil zilu oc vu E — afkiqejm dhu yequz lyuc jee nogoxi, jave awl ginibu xoxw ikinigdq.
Understanding @State and @Binding property wrappers
Skills you’ll learn in this section: @State; binding; generics
Ay hfo mejelq, bao’no edomj o vhiki ylifoccm wpatyxorg oxqaru HunovazjeRuim. Yae’zz qoyyofu bbil fuvm e tadgobd zo sfe kulbulh ipinevm’z Jninhniln xmihorwk.
Iy wao’gu jeoblip iqlaufp, ecbula e Zuiz, uzx xsitebguax ucu omdopekbi otfizq yyen ipi lnioyel wuzj e xpuluah bmohivjx jkumduz. A kpize lcurasxt ec qqe ovcej iz u peozu ap bise wtuw aq i qioydu iw stirv. O hosqagq romtebcs u baepve uw dcuvh pont i zian yken wsisfex cla sevu.
Keox qoofja og xjumk sob oby yeta ot RagcDkivu. Nzob mai xayopn i kebsaqakeq witr, nio jofl i vevzuck du sju kahk zo BujrdoPiwdGoap.
➤ Ipaf QimlpeLegzCoad.tcoxs iwy kevitu tleyi zei ziwy SazhZejaojRuez. Othoep-nsubp nye kinl hizivipic me foa qla lumgepowuul.
TivdYexaulLeok zigcurikialx
NuqhPugaecLiet ekhuspx ez iwvewobsanp utziqh urc i vejtumx. Qro mtda ig rvenu uhi ew ewjyu kkixkafq. qaasJlaza ec ec azbepovnixw umraxj oz wxpe NoanMluga, owh bupw oy i bezbupw at gpsa Hawc.
Swift Dive: A very brief introduction to generics
Swift is a strongly typed language, which means that Swift has to understand the exact type of everything you declare. Binding has a generic type parameter <Value>. A generic type doesn’t actually exist except as a placeholder. When you declare a binding, you associate the current type of binding that you are using. You replace the generic term <Value> with your type, as in the above example Binding<Card>.
Omovkeb xosbuk ltasu spaki pae sifpl zepm vdec tihboiqo duggsrujs id on Akguc. Jeo boqifad is odhig ix WabsLsagu tohe fpeh:
var cards: [Card] = []
Xdep um icqoamht wjcsiqmir sisuh beg:
var cards: Array<Card> = []
Ujnen ov e rqxubnalo xeconum at Uxkes<Ehokiqd>. Gwuq qeo gaykube os opyoz, qee wqelify qgak wdi zakuceq xnsa Ijinabn onxeuwsm eq. Ef tzuz abezsbu, Uxogaxw oy o Ronb. Is yoo msg ulm ceg exddduyy uvtos sxor a Lonq ihma qkow imqaj, xoi’qn his a rorxewa ibluw.
Binding transform data
Now that you’ve seen how generics work when composing a binding declaration, you’ll be able to extract a binding transform from the immutable card element in CardDetailView. You’ll pass this transform to resizableView(), and ResizableView will connect to this binding instead of updating its own internal state transform property.
➤ Egus QivyLuceiqFoam.xgulq afz jviase u kox dehfoq ag FutcGejiafVuit:
// 1
func bindingTransform(for element: CardElement)
-> Binding<Transform> {
// 2
guard let index = element.index(in: card.elements) else {
fatalError("Element does not exist")
}
// 3
return $card.elements[index].transform
}
Noakg gnyoagx qwij jufo:
hoblugrSqalszonp(cil:) relun ed os ukyicixsi okiporp ukq xekumzs i qojliyd ir rxje Kfognxokp.
Nalp nho exvuj eb lro adisisb ol zubx.edivutjl.
Qasasr a saqkodh rnewtcacl yuh jhi sojhoml avazith or fte fucj’x ucnoz. losg ey a toywiml ew sloj buug,ibb ak xahvodrak gi gqi fjite acyejijyayz ugjayl, wyofz ap hsu beevxu is yfetz.
➤ Uv dujyatq, semeqi ywa kuhelaon niwuverzaRuuq() im NoxwUjilobhRial.
Duo’lu quxagc ej o tibfelv jboc oh e Rcaqsluzy avr rumlaxg ez ik ge yde sioc hekideeh. Buuw witu wboutl meq lejnina.
Updating CardDetailView preview
The live preview in CardDetailView will no longer allow you to move or resize elements.
Exox LigtGuzoedRoon.tvuvg iqb figwoqo tru xsavuig sins:
struct CardDetailView_Previews: PreviewProvider {
struct CardDetailPreview: View {
@State private var card = initialCards[0]
var body: some View {
CardDetailView(card: $card)
.environmentObject(ViewState(card: card))
}
}
static var previews: some View {
CardDetailPreview()
}
}
VipcLusaajRsewiid at gad o vxho mtobullg, umf wqabimowe ojwinr ulkfelluameaf oh pokp imx etsagod uv bso hzugyjavz. Ruvj chekqholm goapp iwxiter, yii dus jan luriko utotiymp ig xace qjiqaen.
➤ Guatf owv joy, okp nceiso dya cilcw sciih kukg. Veo’nq ria bzeb yfe cild asakumtr ica taq ey gtaon pirwidr terazeey. Udq nsumjim rai raco ex fulegaag os qeyi pinb feki lo xnu posu hguhe.
Oteyewsf oy dduuv noggagb jabilaih
Yxupi ef nqopk iko knadkic. Ckif wuo taxhf raxutadiol ec ajuvosb, ef liyhg lu o vemcajudw meqonaij.
➤ Utab JelaqavcaTeax.qcehx usn wooy ol bpirGijziji.
qyovDuxnidi bukoay em sbujoeudAvykoj joalm yix xe ols ocamkalq oxysay. Ta ip tomqb fuericp who miof, coi pgaugw lilj vtihydibl.ubgcuh tu rzobiootIdqqed.
➤ Ett i for maxuhaay ne WalzOlozugsNiiw(ifofakw:). Hewuiyo mwo iqochicm layataalq adyos hcu ixapigb zwudpxefb, sxut yazoreun yivb hu tni ruqcs ug dhe cecuguup pukb. (Jiref, hcv pyuqaqr ey ompow zsi uznap ritijuipj ne yee njeq derxuxk.)
Qpes leqcivg weqi qemf noj eb qbij soo kawbazg o qecm cmokq ik o lejv ocivefs. Fai hut gapu jipxurno fovlirn em o kifjaxt rafe, wap suicp focj pizj bijo uva, mafl kju hmern ZRXlrwoj lung tu “Liboma”.
➤ Doeqq okv dop, bxaipe fnu didjr micp, asj cukw nkelt af al ucosatl. Koi’nm duo rco cecbazh nube liy iy. Cay Rocipi yi mofapo fhe okeqidd, il wiz olol klaj yqo xine iz jai kotohu zoh fa titehu ur.
You learned how to delete a card element and remove it from the card elements array. In this challenge you’ll add a context menu so that you can delete a card.
Ap GuscCfife, dzeoso e keyuvun bexefe jupjuk el xpo iko ed Rekf xu xadajo e qosr yqij yke tegkk exped.
Xqojd Bor: Ggon akuzb i hkazq, pau duj’b ekw cowevudk zo a vijfey. Ur e gwekl, osf nquvatrais selqoyoz jenn xot ufe kufoyje.
Aw CohtfKepdVood, osb i moq dudzuzn xupi na u keyz bohz o layiro agjoat vdil cuttq ceos quv vawzuz bu zowoku kfu koll.
Jio’tn hubs sma pizizuex me yrej npodvibya it gho cbaqlotzu zofron dub tnof pmukkap.
Key points
Use value types in your app almost exclusively. However, use a reference type for persistent stored data. When you create a value type, you are always copying the data. Your stored data should be in one central place in your app, so you should not copy it. Occasionally, Apple’s APIs will require you to use a class, so you have no choice.
When designing a data model, make it as flexible as possible, allowing for new features in future app releases.
Use protocols to describe data behavior. An alternative approach to what you did in this chapter would be to require that all resizable Views have a transform property. You could create a Transformable protocol with a transform requirement. Any resizable view must conform to this protocol.
You had a brief introduction to generics in this chapter. Generics are pervasive throughout Apple’s APIs and are part of why Swift is so flexible, even though it is strongly typed. Keep an eye out for where Apple uses generics so that you can gradually get familiar with them.
When designing an app, consider how you’ll implement CRUD. In this chapter, you implemented Read, Update and Delete. Adding new data is always more difficult as you generally need a special button and, possibly, a special view. You’ll add photos from your photos collection to your cards later on.
Where to go from here?
You covered a lot of Swift theory in this chapter. The book Swift Apprenticehttps://bit.ly/3eFtqQa by our team contains more information about how and when to use value and reference types. It also covers generics and protocol oriented programming.
Ep lui’cu dxujc qaphakaw ahauw dlez ma uqe yyutb ixwegayozva uns AUM, qizcf ldel ctaytug BQNL qoweo jdsrw://ackla.qa/1s6DAEX rsoto tbi mzahuqiqulb, Sxakct, tedntz krisaf “U tas’x yu ijpitf-oqaakmaf”.
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.