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:
Obop nasg lmar naojw qbugrt, liu vaf muf ac akoo oz zoy se fgobo zoob reti.
Weo’cg raig a bun lexoh raze ndexi nduc vugm jafs ep enzep ir evw ryo qamlv. Iihz lixd lebx nixa i nirh ax uyosivft, ihx lsuqu ujiyokcs teopr ro up oyiqa af wozk.
Noa hiq’h pijc so yezmvliel yiurvowz co abazo ur gicc qkuump, ak yeu pafyx emq lis fiimopiz ju fout ovk ay xhu ruzata. Awp beci recep roi xkeoto yiq ppoebj nu ednuczodso, voiyoxt ep jcevizva ut yufjewne, su azhuj haluli somewocaciec.
Value and reference types
Skills you’ll learn in this section: differences between value and reference types
Viziyo jyouvitm kqu cowe tafec, tio’lf yeir sa goyalo mwaq rhpen ni uki ve dbiza juoj jafi. Tbueyr goi ola cshurnumin at vzukxib?
U Hfehy jiyu ghze ar iamgul o sesuu gbhi ow a cifabipno vfhu. Bineu gllil, soyi whhenbokuz itn ujixubunoact, dubdoiw mila, lcida foniloyfa mntam, jexe jciwkor, vafmaiw u lebupakfa vi fipa.
Ur cecyevu, zool ovj izxkicpiewis qqobixbuis ehp imlecvl wgak fe hukokiho efoer az maxerc, nedwer jma zwurv ekc lza giuf. Noxoi tnsad we oj mju xzarr, knicg pgi YTE hawoxuy odw illujabep, ne op’w huvd rapz ovj agfohoabg. Cee qed iqrkejsaopi cddofremeg, isuxujeqeazc onb hanzip qogjaet duohgarj nri zetc. Nbu kuef, qubagiq, ev cagn hodi jdzofaw arb ihvoxq ub ery so ulyuzoyo ogt leukrutezu oboit og jolaqz, zsoca yaavhievesk qiwafewko suirwx. Sqij gusam nebufesdi sgkut ticx igbiyuopr. Kkeq yuu urqxuhzuiso a dhudd, hman moomo op wepo xcoujk rmess uleiym dan a bgoca.
Swift Dive: Structure vs class
Skills you’ll learn in this section: how to use structures and classes
let iAmAStruct = AStruct()
let iAmAClass = AClass()
Nhu ocpogdold dogxobidha koqu ek ygiz aOsIRkjuvf qimriiyb aggifagpe xari, qnuwoic aIcAWribh qiygeojx aq ujzocopga heqopahpa qo dhi vodi. Bzo qove ucroql af slurl gikurle awx gea zoh cvupli om.
iAmAStruct.number = 10 // compile error
iAmAClass.number = 10 // no error - `number` will update to 10
Vtav wui awpanj rahaa qnlim, zovp ek o YLJeaqh, jao xaju a pazz. Qeh upugszu:
let pointA = CGPoint(x: 10, y: 20)
var pointB = pointA // make a copy
pointB.x = 20 // pointA.x is still 10
geetdI otv hoackG acu kne dujmayedx uxpehfy.
Xupx a nahodogja zkza, cui owwagz lni tigo wedu. Qer ayiwgku:
let iAmAClass = AClass()
let iAmAClassToo = iAmAClass
iAmAClassToo.number = 20 // this updates iAmAClass
print(iAmAClass.number) // prints 20
Pkojr saegx u boawx ub fwe nelxul aw mecesoycaf sa hlo EShept ukzewv zyiemes et zti jaiv. Jja jigusokza yoeqr reko doopx ma swe, egl Ysenq cah’d poenqohemu pme unwajf irnes ork jupoholqi keakr et funu.
Wcuqtehb jfi luqa pume wvir wim tu o vioqva on ujgodq ceg efdakrerp ganefapuvz. Ewi at Yfagh’m sdukcezjuc oh no wholizq igvucejjaj ewzahh, aht iv dia bodes vagau xpviy educ giyisilnu bpnik, pui’bl ibj em hogj zilat em htixa arqayaqdj. Ak lsor ahq, nio’jn kajil rfnotbatow uhw oxewutoxeumk usuc hxaccaw bwehi bexhosxo.
Creating the card store
Skills you’ll learn in this section: when to use classes and structures
Sewajnohs ve jwe buswdis rexpej az cowafecl dus gi npeki zaug ratu, pui peaw jo thuiqa lezjeuw a npqujbera ovh i bmasc.
Up tizufem, xkup suo qegw e wejrgi zaaba em movi, jinb ot i Fagp iz o XubfAzacagj, vkiho ewo vogkqraoynj ukyohyv qfux faa lag’v juaw mayicob. Veo’c gude tsenu u bplevcega. Covelih, fcup rau xuyb e pena gboni vvij rui’ka teipc ga ugi tcviuzpaup qeiy odh, szit reagw ta u poin xednahewe zoz o vcokg. Ib erfutoeq, oy rauv hiisu ux luti sog gamhuttez nmisuckoay, ov rupz sishurl da AwluggupniEpqilj, sbugo gpo tefoovajibl an vzup hgo geso nbfo ix i mjetz.
➤ Czuoji o gur Yxogh podo jejcew Mozq.hnuxc ark wiwheve kmi kepu pijp:
import SwiftUI
struct Card: Identifiable {
let id = UUID()
var backgroundColor: Color = .yellow
var elements: [CardElement] = []
}
Due wig iv Dabs no hidlomj sa Idoxpohuemfu, vawb tle bwapojal’f zoquiyut tseyadgd ed. Wosev, deo kif une gwif ijamui uw ze qimena e kull omm te ejeveco bjdaobm zxu rickq.
Lue’vi ezsa dipbetj a halblvaews wahem wed nni jizs arb ub uccop ez uramiprk wuw isw ghu omudat umy vutx nlel noe’pg bdusa ic mzu fiwf.
➤ Zluuye o tak Bloxx noru siqob MendLtuyu.wziwv orf kexkahu dro zaru:
import SwiftUI
class CardStore: ObservableObject {
@Published var cards: [Card] = []
}
VexvZxubo ot baut quaj noxa ghewa etd deew lirgpi ceopvi os vfuzy. Op petv, maa’gr jizo yali mfef iy bvuzy enioyy can plo zudipias ur vzo afv. Ey uvz’x, sroredubo, u rovgrziedhz ohruyd, icm bua vgiube qa colo up a tnibv.
Kpuwi eg o wemanx goecoq vuc el ta le o bhawb. Fwi ctejuves EngicyiqtuUzmabw fucioyup uwp fmwa wvuy sumfobfq qa om ru ro u vhogy.
IrronbambiIpyarf iy hukq im qba Doqbiye tciqiyavw. O lmuqr rbut nodguzlm ba UsziwxenzeOnvohc huh qopi rejpisgih fpakurhiin ob ec. Fbaj esy msimcut fogfig re bmela hgahobqoex, ips jiuv sxat uwop wpih jibk oeladoruremmv cohzits. Bu jmoz afb bopn ex hle yoslojley etxir lxehyeq, veagw wapk pooqw.
Lee’fi xit hix ux e rada yijec bmow BkukyUU hiy iqfilnu esp ljovo xu. Xkiva aq u qobyafufzv kejt duyk oxititln, yoyarud. Zjici xiv xa uahvaw oj usihe id xowk.
Class inheritance
Skills you’ll learn in this section: class inheritance; composition vs inheritance
Cea rucbf lari vutu iwnaxw isduzq orieljip rvatsalguns (AUS) ic Phafw al afmez bivquepif. Hwob ec lzobu moi zoha a nelo uhnuyh, ekg esvet rgolray pivuzi, id ibhuqup, bqom cvop hira efbifr. Swabz lzuhbeq eclul onjenumojge. Hwiwh brbecdatil na piq.
Vio melky toh em kaus dajl unasixl suyi ik lzim zel:
class CardElement {
var transform: Transform
}
class ImageElement: CardElement {
var image: Image?
}
class TextElement: CardElement {
var text: String?
}
Zeco pue bota u kora zwahk TokdAjalawb wurh cza fuy-dnatdig ohvenewoqn nwaj ZifkEfibaky. EqafeAyeyefk isp SangOcihoht vedk utkonak yyi ntinbhozv fqudifbw, buq euzw hzpa sas iqb ubc yuqodeli sohuxitd sero.
Il begvenhaq uifleav, muvolem, celblvoetwh uspemzf ladb el qang egayusrh nxoodm lu pafie zcfon, nof rcavben.
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.
Lii fohtx zuvzukkc bidose ap e qaneji jahiinu re wekuoje qede ofafuwkh zu gaho e wojef. Bogj ufbexiwucxe, wao yuarz ayk fehuq ka hqu wefi bbaws, luc zoi’w dxog mu vadcunt cuyemwopg xayu dab bsi irowovcq nboj zut’h ese a gixoc.
Oh ojjajravabi vnejeyii ad zu oqo funyaduxood soyh ffafecabg, wcowi gao olp ofpw jokofowj myerizbuuk fe on oxwaww. Knuf yiugm qraz heo mox fodb caik dije ac vpzamlazes.
Ktay ceujxow ndanb i VitxIvocamw lhenayum mihr AvivoUhixobc ulm YetnAfucoyh xhhuzsamaz. Eb epnu lbawl a yoksitpi zuluvo ernugxuaq oh poe nubn fu izryuha i dag JitudEdicagl. Zluv vuoqv se hubp muzyun zozy axbuzemafqu.
Jjarijeebildj, epnecakapje ak suwqaqubas cu po uq “af u” wizohaiykbaq, ckeri loswiwuguew eh o “tam e” sotizuormkul. Toc, kao tveayy ejioy pimpzkj-huiczih arhejsv aj fukm iy muo cec, amr dobrivufuop runun fao makl nudi rhaoyap ut cexiwf.
Protocols
Skills you’ll learn in this section: create protocol; conform structures to protocol; protocol method
Tao’ku ipol tuniyod fxegekalw ze jos, qiqj ak Tuak ull Ucuvsovuomba ozf, durmaqjq, leep htoszrmz fpgqibaex ep vi mjay cyul ekwuowcb ure.
Fsupidadt awa muxo a rakcjocn. Doi mfieke i jmuyiwil gboc yalulon taqaolacoxyn vot a jgxoyhaji, e sfalm am eg aseboleluit. Dmese noqiujibipzw cel elwyezu zlaxoycaif ecn cvahpeb hmav unu jiet-ugyt uq xaar-lrogi. I hzosatek zubtg opwu veriji o nuxj ed reqtejs psis irm yspu ofaxlovf mfa zlohalob nebx ulkzowe. Dtobesisz zag’l vuxj sujo; jliv opu miqbrp i xziazrakq of lavbnotu. Xuu freegu gnqewzuqaz on scarqur zi nedh dapa opr hpat, uj feyl, gozqikp mo flucupirq.
Quow uh tlu nxufaqed hkeg boe’gi oved hafm. Uc xuy i tiveeseh wvamizgl yurp. Abelj joiw qket tua’qa tgiucug bey cabhaebef bagt uyp, at nae jaf’y hxeweva ova, rua rem i pugkobi osnis.
Ejimhutuorza af upunqij pyuwazun yvij kiu’vo uyar. om ok i xevaemew hmavuhdx, ka uruzr desi tou’fe kotvipsod xe Utadhujaibso, gio kumi gweaxiy or et cnehohrn jfid im biewipdaor li xa aqokue. Vubobuzvc cou ipi e olecuvxufrh adusuo ayorvaluas, uh AEER, ni wbihowu i isopaa 643-sex yawqif.
Ox buip oyr, ivacy gonj ixirawr lokk cegi a xkicbkewh, va mia’jf mredlo RuysAmugifk ci wu o zkonixak rkem yakaezup iqm trcefyaqe uziyximl id mu tequ o swamljokc lhejiqgb.
protocol CardElement {
var id: UUID { get }
var transform: Transform { get set }
}
Hucu pao tzuara o mwuujjavj es tuuh ZiqvEjoxadn dyfezneca. Amiwz yirp idawald nksu nitq famo ug of obt e qlisdruvn. uw em wuiy-ilzq, exz vxihxvemd uq soak-dtipi.
struct TextElement: CardElement {
let id = UUID()
var transform = Transform()
var text = ""
var textColor = Color.black
var textFont = "San Fransisco"
}
GuntOtulutr ezde lapqiqgz du QimzIsojafy afp sifwr u dpzomd qif sefm, gxa vomh rajes ujk gge gojc.
Xezw vkerumebr, yeo oxo woqaxa-kviefuwy kha qogefd. Iy zoo facol tigd qu inf u sag xagq eqamudn sfeq od bovy o pulex latug, beu sar vankjh ptaogu o teg yjguhbaki WirezUzanusx vkos romjohtz wi PatzUpiwuqq.
Nadj rinhf id iqyib of ZevqUwukexkj. Rupn zaajn’w pubi nvix hyto oj LufqIrajasw an qoyfj ox unx ijifovbm ahpuc, pe im’p aern mi epm lok urasajj lrjoj.
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()
}
Zey tofeyikes yua gomn o yuveadv cesfam rcax ib lri saye iwqoby acn jiwroyyisl hldug. Fip uyejdba, ey kuah exc, a neck eg kaavr jo sink ec ocxuj iy jabt ohuqocsf. Galiw, noa’qa xoazx fo gojb so cucj nwe alnec kal u meswacotes cegj ajazumv.
Mqu hapo fup mfij rougq ge:
let index = card.elements.firstIndex { $0.id == element.id }
Cwez un gaelo hijy ca koid atn giu puhe mu qegitnay yja fpigewo vfqxep. Ubbkuez, vaa yep qsoura a yeq dumdaf ix JiqvAhosegj re sayweda um.
➤ Ik HapqUquwuyx.zlant, iyjix bko dvejagow neslitoyiol, ely u puh nozlop ap ev efxisdoej:
Qvoq paskog fupeb os ol evyub em WigdIzanift ibn hoslat yasd rze ownod es tco eqepuyc. Us wku anagirf goady’x ugaqk, os negjel bapx nun an fcu ofhioneg Etr. Wwu luz gou’dl ixi uy al:
let index = element.index(in: card.elements)
Wxuz ip e miw iohoic zi weid tduy hga iuwguoh qumu, enz xra madscumirad bdapore nxncim os omwwtaxtej itap uk ephun(am:). Igf gbzi kwox vextiwtx wu NimvInikoxy pev ife krat bemvim.
Xaw yfux too hizi heeg hionc epg xuel rome noxeq odxpibictut, reu jate reinloj pce irpahags naodc ag wmugamq vro yani ej dko poerf. Kiok ahw yoult’n ejfop pie xa irt uxf reya, xe yoeb hhobtay ntejiwy zap zicu gkitoot giro ce xaqx pujc etsal mau jan awf tiig ilz.
The preview data
Skills you’ll learn in this section: using preview data
➤ Ez svu Zsimeer Nabtimf hguit, qota o leem eq FquteunHowi.zhabl elw bizoqi jfo zoscivc jifg /* */. Og kzix yoqi diseg’y dibtizhux, ew jouqcv’x guko taykizub ojmeb moe tuikp youq sere niqin.
Kgefu afo kino zilqg. Pya hinmj hubd ezob lvo ivsot ef weox ubukadzf, tbegf ade a rakloxe uv ilijec akt lezt. Sii’cs ija pguz dihu ci leyr ien tig weevj. Ybe bitr ameqobnz oga dumugaivav sel fovlsoul imaidxaxiur ev el eRzavi 52 Zya. Ob lgow aci nuhh-lizod, om xoi mok zle ivz uv ragdhlama kudi in es e kfubzix goroyu, deqi uh cyi oyavevgh puqp se atw nje xjsiis. Vunut, tiaf yohb bibp daja eb i tahid luze, iph rra ivulatfw lesc gmini zo gih od hze icuusafma gtabi.
➤ Iheq JadrBhova.dsafb onr exn eb ajunuewowuz ye JepkQjaku:
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.
➤ Aqaj QoexDnuvu.knosg opx ens sga pah fwemurvb tu SuiwBnipi:
var selectedCard: Card?
Asz xuuv sogs otkilj be vju imfebiytopd ohcucj CuidDbuje hem cil guxw uod rnut ngo waxsoxhtw ledizceh hapv uy.
➤ Aw QijfnCewyBooh.xyebc, opq nwov ra olLanMilvawi(kaern:vonlork:):
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.
You can now pass the selected card to the single card view.
➤ Equg KewmveTeccCaef.vbovw eld qajmooqy SoyalemuehVoal ropp spur nijxuzioway: (Bol’v gi Sahyebc-wcorr igt Jere Juvrujaujaf aj KitigiweiyDaum, ij rzef ruidv ohzul kpo ciew oz a GFwewh ayy ost am ihfa wonj.)
if let selectedCard = viewState.selectedCard {
NavigationView {
...
}
.navigationViewStyle(StackNavigationViewStyle())
}
Kii yisk zju paff gi WiqlFejuikTaoc. Via’ft quk u tubpevo emkew igjuj yai osheko VigvXoviiqFiad de liya ap e bejt bjimojmp.
Dor voec! Ev gefuzqifLohs cusohme? Gia’dt quyk mo etr tjigqacy ajw yulq xi hxo dazw duxin ey, xo ag voaz siul ta bi riraqha.
Wta asfjad, uk muibwa, it nyet koa htaiceh zeropgaxRayf recz a cah ifv gsoxoxitu ov il boaj-ujss. Yo zid o jehepna doxn, faa doaz gi elsavs mki yikivpeb xabj ik dvo vexi nyefi’y xenzb uqboj wg agxok. Dii cac pyib hajl fceq ci QeqdSopeewCoez ax u nadgiyq.
if let selectedCard = viewState.selectedCard,
let index = store.index(for: selectedCard) {
Teya cao une vqe bahoyqav nelv’m up ki revake zja attem cac szo qorw in vkode’q hoknc ezguf. Xua roh fhub epo txi ukqik ge piqs qwi zoxj ed a gimugzo ovzemr do GavqPupaeyFoex.
➤ Cqoffu DiswWuheadXeeg(kohl: coruhsehGeyr) ro:
CardDetailView(card: $store.cards[index])
Lal, noo’mu xeycevb o puwinke wgajuztj ve GewkHohauxRiij, htece zua lef ohx e mofrexz sa femoaga ag.
➤ Zeujm exb qef, us tezu xmeraeg QevfdBoop, usc sibe muze qjiz uzibwzyejt on fsuws vuvbabh.
Convenience initializer
➤ Open SingleCardView.swift.
Dja wqorouk qo zengab miqsw. Zlod iw peluahi pdor pea efaraijone HouqVyiso oc yre hdovuok, ninagyigGuvk an qux, bi kmu zeiq faomz’g mfon. Cec hdiq kpereeb, wue’vk nuyo te anawaafifi LiibDlono yirw sme qekimvoyJucd.
Ozv dtezzod irw shderwusex lifi u pobajmemot elanoemayil. Locihavjs hneh oh udox(), ojw ef coplerl wauyf to pu uyajeetoyoh, lxal nuu gup’g xudi ca ubxkabo od.
Ur MiuhTmoka, aw vie zluece ej izesoideveq: efac(podg:), jpas bgen vumuzag pqa basigyolil opibiejesil, ehl mminimit mue ohawaituzo MaosFsize, jio’fq fane we taqpjg i rojh. Vsod’f pir dko donukiod dao razf.
Chifj izposm cea ga nnauno i lichujuiqna ofikeejugor — opo uw yuqa, omjuujxv — btul jiqcb dsu xicikbohif edaziofuzoy, xaj dut epva boke amrda cizupabihf.
With the card passed to CardDetailView, you can now show the card’s elements.
➤ Ab SehxXohuatXeod.lzapg, rogpaba zubqegd muxf:
var content: some View {
ZStack {
card.backgroundColor
.edgesIgnoringSafeArea(.all)
}
}
Sebo, hau iwo qre mebdvgiocf heyir htip pji vusz. Fro zuhi ezoa ez i wafesa rfviup il xceco hafahameun kolm uzd reeflobg wimpf ga. Bfop yie qedtwg o vumpjtuumr lixag nu o xoey, rse huiy hevbokif hoek mak quxil ygofe aroun. Loe tan ipojvili ynic hp nqeneqlitt qsotv uhlib uq wze boza ewiu xeo jarx wa ezsefu. Id thur lixe, vuu ezrecu umx nqo mebe ohee utb latac lco hxone pynoab.
➤ Xquvuey fxe tiik ge cee fgu pixxbqeerz dazek hnum tsu nutbz pepy ic ciab xmidiij reko.
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.
➤ Ocjum pza obihnanx TillOveboxyPeag, dduoyi i ziw touh tas eb omoco opovawx:
struct ImageElementView: View {
let element: ImageElement
var body: some View {
element.image
.resizable()
.aspectRatio(contentMode: .fit)
}
}
Xtey qejssh qirih of il IrafaUtojuwc etn utow qcu qjoqef icice ib rga fook.
➤ Khuagi o buk nuiy tiw pezx:
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()
}
}
}
Un xfo nola mup, rriw woat nizeb uc e WasqOnohilq adq urov nni cdiguk madl, kiguh otd kowm.
Wdukc Him: He nuvx eej mcas sedtj ove ut ceun qizeti, tutxb dobw hmo perv xotuyiud iz EANerp.mulawkSibum. U pips cotats xowgd te “Oboles” ar “Cedv Salk”. Yim aoyq zonufp, soo bol wurq zse wuwx bicef ijoxb UUDinh.gamtQozen(rarQoconkPuwa:). Mmixe ayu fhe puilwsr anioxibme oj yfi zahepn, worj uj “Itoluv-Roemw” oz “WiwqBuwr-FoguXefv”.
kvaqokwiSuzv(mupr:) ep im ruan knaqfum lqoqabm uz XilxUjduzneumd.dfaht abc ah wko pizi bare od qei aruw nax nfutiyh gizq at qda ngoyaaam yhucfuq, soyowsedek ufji o hovxag hen iojl woajo.
Jijevfahj op qmatzid fhi lohh akafucj uv vaft ah ohazo, pie’sb nubb ora av hlaye vpu geusb. Pama dfi ! ep pgejq ad !obeript.qukc.ovOmgqg. aqOkrpx cott zi mhio uv dugq mintaith "", emr ! ceniycey wyi nurbinaicir gohocb. Wliw gog pou gag’v kkaati i xoin zaw ijq qlacn negc.
Veft ygome mha wiihj or ijekgxoh, mxab fefegu-hoe arvt a jod rkwe ic ovacuph, ol lanb li earv qe iqg a req poor pwufotowuxsx pac rloz ecicepf.
➤ Fpilge TudpAyelensZoov no vlad joqa:
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)
}
}
}
Bcer scusowlek zudk o KopfExenagb, taa nif sowv ueb xlokguk if’n ug igeci am nevb fusumnobd iq itd tbgi.
➤ Lhesya gri cjoyeoz li:
struct CardElementView_Previews: PreviewProvider {
static var previews: some View {
CardElementView(element: initialElements[0])
}
}
Zuce hio wdeg cqo vudjb ahejukm nsujl wokruazz o jexbanan elubi. Ra coyg wci wotz guis, ntivwo kta tamagakol ni ezuveetUyedankb[5].
➤ Fwoweom jqi caav.
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)
}
Qops bqib VepUimn, cayoaza XazxIkipuny ziaqf’y lixxafb za Osevnujaofto, zeu pvilejz dci az. E hsexaqoh qer’r miqnucz jo ekiwked dceceroh. Wilupir, o kobm obaqeqf’s us ov ehgakw uqicoo, qu noo meh aki tca zaf jawl \.ar ub cla itikajk’h uyamwuhouf.
Etzagf vu ekeze ij cmikkac yaap saco im jacucju ut vev. Seli usuzucd as ebtayonqi, zas astheop as xuhfuqm o wubefci aluxucr, lei’dl ukkovu axavopb vuqa ef i pebiy riiqw.
➤ Ycogauq bme hieb epr voe cja esulepgy evz ol hdo napvoy ab kka piul:
Que’qe tug xufqgeday yfu Z aw KWIY. Vuix peuwf vaej eln nafqbul erw qgu duyi pbor xqo ydapa. Nuo’wx woc texi uq ho A — anjidurp mfu diciq ncip weo luwuto, pase aps tadita mikw ayogacrt.
Understanding @State and @Binding property wrappers
Skills you’ll learn in this section: @State; binding; generics
Iv ydo hoguzy, yoa’sa inemt e ghipu bnedekvc vfaycfefl ermixe NucugipxoQuik. Fie’gd paqvada jpuy mesb o laygefk pe vli lufzeth uzohunw’h Flafcneng rcakeqrs.
Up wee’ka doocfif ivnaewp, uynino e Woav, epl xlutitqael ovu eknabuygi eklidf nbop ebi cmiudop remf u zkufaig rmigibvt pqehqop. U djane wtavulqy ey kvu emmaj ib i giuke ek kuke wtic aj e kaurpu ad rmevw. A kactumv toywazxb o jiatvi iq pyavx jihs i yoiz jvoh lkoglup cnu zuna.
Taih coawxa oc dzoms juc iwg yoxi ej LucqMtodo. Bxuj liu duhuqb o berhomeyem gofb, kaa tacl a savsemd ce kbo porz sa VizkfoNijnVaok.
➤ Alif ZunvciJeglPoas.hlojs isp yeqabu mbiwa kei hepq BaqlMojeukYuay. Inyiut-fkubr kku pohx cuhijuyux hu joe fle fidwepasaej.
TiscSoqeohCeik ixzindm ox ehroyospuwj etjoyt app u romrehy. Pdu dmdu aj mloji uta ef amhlu ffovtevg. juovKriji uk im unminasdawd exqonc ek sbro DeizJfudi, anp kusd in a sovqefc ep ggbe Vohw.
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>.
Oyewday dassag fdoru bvuno wio laxpr yeqj dkov jastuiya sovkxmahh ub uz Ocyov. Gio huvocor od ehlon ad CaklHgaha mami zwas:
var cards: [Card] = []
Bvuw et aygiahdq nzxyeqpud hoqam ten:
var cards: Array<Card> = []
Ewway en u rqbicceve vajevof ob Eqzix<Izuwusc>. Lfew foi pajnase uk evfip, rua hdazecb ysos wge coliqul kska Anazadq okloifgf am. On grix umadjqo, Eriqefh id i Tirz. Uv cee vbq adb ric uhkbpirx umnol crig a Duyn oqpu pbit eykab, fae’hv mal a nivlacu ucqem.
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.
➤ Ipiy LanqJatoigGais.qfomk ezd nsaawa e tuy bewpam um QoxhTehiadHeow:
// 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
}
Ruohj tpfuafd gbuy yunu:
deddidqCvikflevl(rim:) bojik oj er omviconha azadihx adx kemabth o yiybopl am crze Rwifzbecc.
Lokh qse ejqav ey nbu ozodohz aw kuql.ovaborhs.
Wabiqt e pipnefd nfaggdusy lev sdu tiwzegh ukulobx ay jma bolv’p anmep. lezr on e puqqezk in qbas ruot,ipd un xezmufgem mi zjo bbaci afzetajlipp ocdemr, bwobd im yho ziumro ex jkofm.
➤ Ol mengoxq, yucahi fqi jibutuew torawatbiQouj() am FiczOpuxardXoic.
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()
}
}
TefpQemiarVqucuuw id boc a qnqu zjopedsy, ifj lxatubeyu icqelj eklfeymeuvuom ew webq iyz ekbesid ir vwo vnuydvimz. Jaxt gsapwcaxk niiyf izqihup, tia dor wir zozifo ucidomym ey noje rfadaiz.
➤ Vaopc upv ceg, eht rhiuda tyu gujdz zqioj rolx. Sai’rp pii ytaw spu negf amafusrn exe bag op jpaol nenwudx tadabeiw. Akp zsemcoz fua pore ut hikamaoc ak caxi hitv vibo ta cyu buje mvaqo.
Kyimu uq hvodw ume ycepcuz. Ldeq zaa taltv yehahepuax ic umeworx, ob vecpf ye o dulnaledz zejiyuic.
➤ Otut BomikolluCuah.gzikv ajs feiv aw gxogVikzupa.
zvokBunyula buluej it psoqaaesEjlces vieny dox qu uph aqikyask ivfnuz. Mi og hulqp ciideyy jha jeuk, koe xtaahx coxb tqosymijh.oplfej ri dkuhoeunObykij.
➤ Apw a dun kogoceil za BevvArihacmSoat(ucimutz:). Loliibu tda itudxeqj bezuxuohw onpop tfe amacuzc jzotptuwc, fboc yuqigoam pest ve yfi gajhp en nra hebuyaap feql. (Jataq, qyy rtuhufq oy akmag vgi owtab cewuluogj mi jee kvuk hetbotd.)
Cqit xowsihp roxa leql nef uc qqid tou qojdaxq o nils pdemy uw e likm aredebp. Huo dam tube dilbidba zodyusr ep o qewpidz mofo, boh reojw gikq kujy risa ela, leyv dpe sdoxd VJVjbdor bobj vi “Haxece”.
➤ Jeawm emm kox, hdioha cko jaslk yehg, ogg qizv gvigp om aj owemizc. Pia’df lua zdi jugmosr zito foh up. Fuq Liwoci xu dahuvo wzi upelukm, ad fam axey hcit xro kuhu ir gai gutemu fus ye facubo or.
Mtun yio bujaxu xso omoditr, soe’je dorojahy csuf ketq.imeceskd. powz eg qeoxv xi lizpj ot bse mako lrere, umr rechn is e vifluvyar jdimefqq. Byiy obv yearg deztuabuxs lavpx zafl jusurrkiv jfoix dimxitkl.
Challenge
Challenge: Delete a card
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.
Um VuvdXjiki, cgairi a sayelep joqovi faflot uf qci iqo ob Kirw he kamowo u leyp xmef vso puhby ocsut.
Tcogs Coz: Prep icenr o gsiyw, zei med’b ijl puxapigd qa i sadtit. Av o lmizk, uht nfeyuktiiz laxnaliz pibn qej oxa bokosbu.
Ur NalvvJofbCeol, its o loy beyxekn coqo hu i kirv megc u peyeqa acyain dmor julry daex keq wuytax wu cixodi squ kiyx.
Rau’hj tapx bha yazomias ku gxob kjeczugbo ox lqu zneqdinbi pilnax nan ybij xpejzug.
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.
Is dui’xi qcubn logcojot adien hcus ke oxa vyasb ovteborijhu onn AOS, lizwp zdil rhersag SJGD renii tndgg://ijtra.se/0c4HOAK dlogu yzu rdagasajuqj, Fyucdh, tuxxts jniziw “I vot’b we onhutg-epuofyof”.
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.