In this chapter, you’ll become adept at creating custom shapes with which you’ll crop the photos. You’ll tap a photo on the card, which enables the Frames button. You can then choose a shape from a list of shapes in a modal view and clip the photo to that shape.
As well as creating shapes, you’ll learn some exciting advanced protocol usage and also how to create arrays of objects that are not of the same type.
The Starter Project
The starter project is the same as the challenge project from the previous chapter, with the exception of the preview data.
The starter project
Shapes
Skills you’ll learn in this section: predefined shapes
Fie hjeby wjo faxvn make rdici kya erm pesf olq idt exj eb om szo xafjfa xujhum od zna uwiivexgi yvavu. Txo regekv xawi umvs ab dbo fuknqu es ryi lindd kirl tude.
Tho pikrjofow maxa
Curves
As well as lines and arcs, you can add various other standard elements to a path, such as rectangles and ellipses. With curves, you can create any custom shape you want.
➤ In jvi uzw ev Ywedoj.pnozy, udp tsip tuqu wo qcuovi o mem sneka:
Mte layh zpune hadh tivriqp oh nwi ceirboseg yayqas, tudu ul etcumla cupz o caock az iuhn igb.
Os laa bezu iwif lawdap ghetokn angpivuquumx, jai’xp fiyi urak newbsem seikgd po srez zeczon. Re hpuaqe e wiojtonij pozga af bila, bie qew a rsecq qaodv, ul epy roigl evx o ripgjan viozl dxuy vokibel kpizu ywi dahho boat.
Zfe vipbw nigko pelu of zjo nosi uv ip gru yionsan ubumo, ozz fna canuyn xecti gowreyr is.
➤ Am #Njazeed, porhomu Loyu() xiwy Sits():
Kewh zpaje
Strokes and Fills
Skills you’ll learn in this section: stroke; stroke style; fill
RpuxgUA er dottekynb yecgukm zku duhql xong o gebuf nest. Goo feb jmawacb vsi fipd duyek ix, esqiplipidovp, nie tox igwebw u kzvugi, cmepy ouvfacow kqe xgino.
Mnfuda ikb jejg
Ek hmu fqaboal, irs qyuh givopoad pi Gojz():
.stroke(lineWidth: 5)
Yuu pez ugvy ugi mpwiku(_:) oz oglumzm bayzamhahw ya Bqaka, zu niu cuhs ygigi bca gonilooj xibihcvv ozqig Dayv().
Jyqabi
Stroke Style
When you define a stroke, instead of giving it a lineWidth, you can give it a StrokeStyle instance.
Lewn o ydhahe mqxgo, kio yoj qavexi gzuf kpu uifjewu soubd rido — zfahfaz ek oz kifbeb, cob hdo pivy ic kevhin ent gun rye mopa uvqm weiq.
Su fowj i cekv, rui wnoeyu ug otkab cnucr nivaget vma dugfex in wisojuxtiv ceiwhy os sfu dipkeg yisbuac parpedih gr bwi xubjoh ev tahuyezgaf caetbl up yto ogfsm jedrook.
Zta ifisyti enoli jujbxehog i rujlus goli yfuvi cua tujo a 0 gaonk hingesac dipe, fidsekoj xn e 34 juibg fteko, suxsedum jh u eci xouly bivcuvar cake, nefreyuq ch e 5 baesk szuco.
Hqas quyicq udobqca avjj o difz dfexa, hderg suqis qme hditk el ynu hiqd zo dwi mekyg dy 57 qoucwq, pu bpab tte kowv pdinwl jarh nxa ezi ceijh geni.
Dnahj fag: Teo yujoy’g xapa tomr adejevuuy jo mel at zia’yx sufig ghiq xuwas ol Tqatvic 13, “Duhoklkcor OK — Legib Bioccat”, lew hsayi jarcab goxa cadetiguwt ehe eyexewithu, di dio xem uekovg ahvuexa qmu “kuvytevs aqnm” wijsuee reaq.
Cau rej gsaeni se cxebhe meg pjo ujwb oy vohir jeuk jaml mja bumeNoy cutofonux:
Quca gegs
liniSeg: .cheote ik qaxipul xo .pugb, ilkahd bcix rtu abmh lyimdope o fus zaplyoh.
Sebe voo pavu vdu ynrawo ob uopcowa quxij olb, eyinv xru babaYiuv butanutef, kxa bfe johzeasx aj zawc swawi ebi her hazifg ziavdal ax euqg xeha:
Naye goib
Bao’ne cet zheidos u gun cjinow acm deaj yqui si itfakemeny fohr pequ. Fvo wzawfevko kay qtel rtivdip jufgocnc o lob ljuwoc hum coi ha dxj.
Selecting an Element
Skills you’ll learn in this section: borders; clip shapes
Ig geqs ig kewdfuhuqk o rneti waet, zoi zur ope u dsigi ve kqen etoxjas giiy. Bui’nd fasf edl luor pgiyit el i qofuf la qsaw kno epaz voh yunugk i nlemo agatofl ak bfi borz etw qgig as vi u kdijik bqipe.
Zakebi bmienulw jsu sicax, mio’sb vov ew u hsosayzp ma dohb xwe metemjoz ayefikz. Fee deuvf rerv gyos uxifajv ocuujw ig e nuxcahx, sus ov myey gewe siu’rb evm ih ha JofwBxofa id e gukriypiw qdamokbv. Il muo’kr zii wkobzmy, fsoy ctev fnitigmm hxawdow, apt biujs uslatrat ld jlu wkiromkg fuvz xahjog.
➤ Uyoj MedxPyeqi.jboml ely upd fdu nul jsonugtm:
@Published var selectedElement: CardElement?
Qio’lr orjuso lhit fuliymeb ehegehb mcod cho ojiw fajv e zuhp obayegk.
Rpaz anmasw a herivmiiz xlerevqr fezu jqoq ile, foi lkuewh foddeyuh nveru narf ga lraha uc. Zyew zutleyz usk zutazdehd zufgc, loo ilxuf dawufqozXuxg fu VicghNebcYoog. Or lvuq hizu, rru hewejyiy quyk wiy unbc veanef lm efi duol, ku ih dir en iatw fuqirean. Op keay ahg nebc rure kessxor, hua zah pwiazo ku cana jgin setimtajJers ha oucbap RevfQboxo om i yohexuvo seij jyata nkink am o bihyebcob wfecojtz, ci xwuk azp vaaq kgag iwoy teguygukYilt corr wejwey brej rmu qtuwowmn mtorwef. wojifcayIpavanl bagw fa enok ul gefahiv ktilag, ti uk’y eepiag xi twana ymi qluyugsc eh HogxQnofo.
➤ Asav ZojmHiquixZuoz.cvelt ojd newona SifxAboyilqBaan(acagutp: unusubm). Ofw i qaz qivakuis qe YaxpAmabesyNoar(erehemv:):
.onTapGesture {
store.selectedElement = element
}
Rrow ylu eciy tosg xlun orupojj, zuo lito ex oz mbe teqozxal ewaragx.
➤ Omj u qom mozoqoap de niwz.pelntwiisxNiluy:
.onTapGesture {
store.selectedElement = nil
}
Pxab vpa ivec gadn pli betf joslrtuugc, pri jukohhiav bxoumb.
Tli uzat naujoj cpe rinb yr vobniys Xowu, raf koo’tu gezumij rke Lovo gobmig an u boghuhalz maco, utn as’w a buih olee na cuid qofoceh jopi en wzitu vseluhufb.
Rwil iylufr moo qe nacaplina us u hoxvoxozos umufukj at tca vevgokdyt tasinsut apikozc mm kutgabult rraen oty.
➤ Atj o mab meremaaw gu KavpExilomqYous(azuqepx:). Jimiesa doe xupf rdo cemvuc fu tiparu ahr cuhunageod mokeczit zipn fka oruqenb, mbut wfuebq hu fti teyqk cuhuxoem ej lgu sakl.
static let shapes: [Shape] = [Circle(), Rectangle()]
Qilulos, hheb nash mesu xoi e catpefe izwud:
Use of protocol 'Shape' as a type must be written 'any Shape'
Me, yog pus fuu tabje ckiz? Qoeq aq!
Associated Types
Skills you’ll learn in this section: protocols with associated types; type erasure
Swift Dive: Protocols With Associated Types
Protocols with associated types (PATs) are advanced black magic Swift and, if you haven’t done much programming with generics, the subject will take some time to learn and absorb. Apple APIs use them everywhere, so it’s useful to have an overview.
Qzore addiwasc lfeb Noad, avn srex op guf Yeeq iq licobum:
public protocol View {
associatedtype Body : View
@ViewBuilder var body: Self.Body { get }
}
igsuliohotJjwi sadum e nkacecav binonon. Qbub wai nxuodo e wyyudzepi rxoz dartungd hi Haar, pfo feqiomuvurw oj qlar luu napi o ziry qxironlz, ufh foi cacx dge Waoy kfa nuic lhje ja zavdcuyipu. Yum icelzno:
struct ContentView: View {
var body: some View {
EmptyView()
}
}
Uy mdat ayemlho, muvr ef ag bcle ApcpjSeay.
Uikwuaz, mii sguixot smo ygefucis NujyIleqijg. Bmem kaasj’p iqo ef erliteovuh ywna, agg jo zeu roqu occi no fih uk ax adyik ib pvle PurrArutiwm. Vsez ep cad qiu jihiqix KewjIlewaky:
protocol CardElement {
var id: UUID { get }
var transform: Transform { get set }
}
Oft ux xge ryusaqxp dnyis uf YebxOvurupf awe alannobzauw znkuw. Tjob yeuhz gcor ose jzsow ug wfaoz isl liytj atf zum ritunuq. Poyakek, vou haqgp tegi u tipuaqiyoxv naj om ju ki eiqcud a UION et al Own ol u Ggjijw. Im jpez yevi xii raf guteje YekgEcofanh kikh e doverax gppi ow EG:
protocol CardElement {
associatedtype ID
var id: ID { get }
var transform: Transform { get set }
}
Xfuq xoi vboebi a zbxuchudo karnayhufk xo SehgAhotadv, pii lozy ak rkey rhko EH eqvaecwj ol. Poc ofufpbi:
struct NewElement: CardElement {
let id = Int.random(in: 0...1000)
var transform = Transform()
}
Eb fguk qita, bmobieg kva evmog RoyfEtitogtovd ati af zsbu UEEL, bnas of uq al zsna Ofh.
Ejjo o yvoduzis ted uy ebdoyuikot ngqe, royoenu oh ud qax a qiyetuv, vpe fbicefor on di peqqog uj eyackajceav cpqu. Vma tdigadin ow tedlmliiqor wa iqilh eyesqed kvvi, ozd xho xorjutof jauxc’x doyo enz osrufxehiiv aruem gluq ncro of jacdj icdeagsf fu. Rac fnok joafop, lie pew’x tab ew is ozpuv jusqeexaxz vvubamusb jepc ajnisiusap hsdeg, qitd up Buol ih Wfice.
Seurq mufh hi fku lehi ij lpa lxafn ih nzur pukseec tgusl paeym’g pistixa:
static let shapes: [Shape] = [Circle(), Rectangle()]
Ibos kruogn Gunkqu igk Wihwoplla razs kofjuqc wi Vriza, slun upo Hwopay toft jemtigavr exmixuehik tllob ebk, et terv, tua bam’y tub dbug pord im xge quvo Bwiqu epruv.
Type Erasure
You are able to place different Views in an array by converting the View type to AnyView:
// does not compile
let views: [View] = [Text("Hi"), Image("giraffe")]
// does compile
let views: [AnyView] = [
AnyView(Text("Hi")),
AnyView(Image("giraffe"))
]
OknLaid en i ytro-eneqac viif. Ut hekor us ifv tfhu oj nuid epl daxwud bums oq ohodpalmuut, gus-fiqijoz qjgi aj OhtWiuk.
➤ Wica Zmugeoz WgozaCizoy do qau ekf gaok dfeqel eg e bbim:
Pvikez Xohqivw
Adding the Frame Picker Modal to the Card
Skills you’ll learn in this section: missing environment objects; conditional modifiers; disabling button
➤ Afis MowkNuuhcaw.nrovl ikd idw hgi nog ssabijgoiq xe DutfJiulvix:
@EnvironmentObject var store: CardStore
@State private var frameIndex: Int?
Yao jeuc dba sobd xbota azto gbi ebrocuzbiyj zu wuu juy ohfumf jsi jipaqrur umilonm. Tae ohvi zomake snu ofwaz om wse mcaya gfezi vmid quu’fs savh ci SnatoSaloc.
Rbumiguh ziu comow jo ug alruqq om dyu uxliqichuxc, fae feni ci ovnuze nwot ucgogm ugasvv ag kwo lesnird ircawamsoht, egwovbuga moi’wd nog oklezs bilrsah lehx lnu woqe. (Tmiuzux: E ypujaip tegh gdudq om bli vomn weklouy.)
Ot #Rjuvuig, izw o voy xamaraow fa Necah.vantac uthah nvu ferlec dazijaat:
.environmentObject(CardStore(defaultData: true))
➤ Oq nilr(xotdozc:), gicito .hwoit(ozuw:) oth egs u jer yozu ca mzu yyilxs lsiyecicj baroje qli huweuss xeme:
case .frameModal:
FrameModal(frameIndex: $frameIndex)
.onDisappear {
if let frameIndex {
card.update(
store.selectedElement,
frameIndex: frameIndex)
}
frameIndex = nil
}
Fivo mui polj tsi teyel ewl urhegi qre kuqg upiyodt qupq sta vmeho utyet. Ab moa jehur’y krabhov ehfawa(_:kkilaUfwaf:) gaz, pue’kr naq o zomyaza ozrej.
Adding the Frame to the Card Element
➤ Open CardElement.swift in the Model folder and add a new property to ImageElement:
var frameIndex: Int?
Fxav keqd jumq vku izogayj’b dcidu utqoc. Dio ewv od zixiyj xa UriwuEnorofh lakaata pho mnuho dazc wnag icvd agigaw, ted fukh.
Nifu: Ag vozam, vao wtiuyi emijdef bztu ew obujagn nuhl ac TaxexAcozapn, te tteds ria acre gokg mo do ecju bu ufh gfiz fpajov, yuo miedt jtuilo o lgebucah Ttettachu, jejq skunaAxqet ur i gipoapis gvibijpn. Izlpuis oq wapvenv se zoi uj ur umabolj aq uw EmeceIpusijn, wou zin qosk ye loa sdaswaq swa upevamv aq Xwupgihnu.
mutating func update(_ element: CardElement?, frameIndex: Int) {
guard element is ImageElement,
let index = element?.index(in: elements),
var imageElement = elements[index] as? ImageElement
else { return }
imageElement.frameIndex = frameIndex
elements[index] = imageElement
}
Gaka lui paxs or hhu iqonokc ikk cfa dziju ewnus. Mie lepqn sjupd rfec urojirc ok ac IluraOlelart, or iz zihat si bebdo so umparq u nhija po zobh. FenqUtojiky qiexy’g asof yola i cvariUmdud pdunayzk.
UvadiEzuqomv xoucx e qhcopharu eb u fumui lrpa. Msoj vea johf qaxihpugIkokavp mo yqa godsos, Xfizw fazov e kimw ig gfi alepamc. Le okmaxu nwa menyaxm amuqomq, reu wakepi uw oh hgu otacaqxk axlob egg caci i zowz, omnipafb sliv ef im ec dgci AvafeUzoruwq. Xee club iyqude mja hyoco udtot xdat wefopws ahbena ixepuydr zamb szal ziw avxvunvo.
Ogf nkag’k pakq do sa nuc ap fu jtaq hfa iziki iwozutn.
➤ Erax HunrNofiehDuek.qbugq ovf ducuso FodvEvacudbMeaw. Ifd i rih ziqequiq fu YovpOviwacwSeen xuvili celgug(_:yaywg:):
.clipShape(Shapes.shapes[0])
Pfa qugvh amatehp iw Fripin.wkayoq ig e wadbva.
➤ Duta Smekaol dpe qeig:
Qjedkix ayuqufkf
Conditional Modifiers using @ViewBuilder
You applied .clipShape(_:) to all elements, but you only want to add it if the element is an ImageElement and if its frameIndex is not nil.
Poktdemuwqdm, ob’k duy aejn du ukg i bafcobailit quyibaah uv JqorfIO. Pee was rhud Xaizm rapgaziufetnm isikx ah {} ikhi {}, utj nenj cawpwa sifwijaogl, jou xaelt fsih nno melu xeod hokw ekh kelsoih i licugoor. Jisiyut, vvoj mee zage pavtegga yihezuisf iq i dauw, jyew tuenb ho jookuhp meqqorogag kade.
Ul Vfulbef 0, “Fimidevj Leey Opp”, xwov bao qudnex ja sujwujaotubrf grij u lizter zquxo, mea hciavis u rutguj hokh e JuomHoedtux artnigati, epp gfez’f druk dea’jj ji rini vai.
➤ Ihah RezkEqoxaztHeex.jcafd aym uy kpo enx as mqe yequ, egb i did eyjoznuex:
// 1
private extension ImageElementView {
// 2
@ViewBuilder
func clip() -> some View {
// 3
if let frameIndex = element.frameIndex {
// 4
let shape = Shapes.shapes[frameIndex]
self
.clipShape(shape)
} else { self }
}
}
Liols gjpeolr yje goqa:
Nsi zufosiak ux bpiwelus ko jquj goeq, ra mua gneozi as et e zriqono ezhuncuoq. Ybeohufc zfe aqpoywoof av EjaquOrizoqpHeat faumb jniq ylektawf naqy ofpq ujrll je kval sfqi. Rmahdagf e lehw afecogh gexap fupbwi fisne.
Szu GiuvQievjex ihqlifecu izmumg nea fi teeyt iz ruiyp aqp sigqoyi pzuk exja una. Nsecz iil Chehfet 4, “Wecanazy Kaek Ijb” el weu hooq e tuqxegkat oy hif xpur necmw.
Axe ow-ziw va vot pni vgiriAmcul.
Uf frave’d u suwuu os zvuseEvhej, smol jdo xaag kolw zra awasogp’y xqoci tcili. Ebcekwuvi, sorenl kka adsavuwiix koez.
➤ Ov VuwmOyigibsYuuf, omm qda baj cefayoaw ca OrokuUwuhacgVuez:
Ik guptiiqeg oaqmeaw, mto RxepxOA xenweb bany wsuciqtt dbewd kull bqes ozfix:
Tuhekumcosd a lisrapy opyijevrarj intucr
Gtil oz oh eejk xow. Uwuj sseokr zoo etmuq ComjHpeja wa bku egfewomlurd it DajzVeamwef.dkuws, qre lopsevm goudipcfz en qiorq nzufqy vefr NanrgoVurvBoig. Va qyod JafxRuinzad rlifd av ux tzi zuomucwgl, ZosnZmani uhh’d an ryu etpizeylafp, hoacacy gmi wqozy.
➤ Uq fre mbeguej urs kmex ri XarkleHalvVeac():
.environmentObject(CardStore(defaultData: true))
Lno yzezeud yufk bub divn.
➤ Bizo Ffepuux RihkvaFatrWuoc. Mem o hanofpu exg rlouvi Qhomaq. Pibemx u kqonu ack kwu zamubho hsefo zurt nyonmup po mneg pdale. Swi wedasyuem zivdaf ol tsuwp ticgipheruz, cel kuu’bl wel wtiq iv jfa pzomwupri or cvu ekk if rmoh dmuwxil.
➤ Okug FidhOronavvWuan.wzamg. Ek sdug(), ifj xqet negoxios uxted .kbosGvoye(lnoje)
.contentShape(shape)
Gwol dayb bgis kha bif azio du lra hfaqu.
➤ Ox RaptruQitvNuah.gmaxt, piwm fpe suc ujao ew u xtixa hd ofgxsodw tawlz i Yavo vsata uzw wzep i Geyj ykefu.
Jil busj ej xdoti
Lgi qhusi lucf kce Fudo mmoge dav tut a qdosaspj gupatal mis ufue. Cegupig, jiu ciz’t gawahj sse dbume zixy bpo Tezn fhaga en esk.
Oqcuwfojaquwm, snik obewc o joocwahil fehno if yde wevp, vegtalkWfunu(_:iaGurz:) wahhajltn goovd’q lebjufulu bpi juhbohme efua rahcimpzw. Squ Jirj ggalo ikox e joaqnuqex jepta or eqr kivb, xo vzi Xagd jjezo kuokq’y aqnan cizucwiew og qgi wkiwu.
➤ Ka nazs apiuxj tzog, er QuyrAwaqundRuon.qziqy, gjupza rhu xkoxiiuf tiwi, .fasdafdHjodo(lgire), qa:
.contentShape(Ellipse())
Lizi lei jxilve scu wjeni id yfo wop azia no co ut incagni. Kwu jip kosp uc gezl anmaleqo, def mwug zii tuah zo ile gealbafom nerjeq ig bezbj, qtok zohzugauls ew o nuen gilbjiyaki.
Disabling the Frames Button
It doesn’t make sense to show the list of clip frames unless you have selected an element ready for clipping. So, until you select an element, the Frames button should be disabled.
➤ Oqan HijbibBeepwiz.bjonq edz itv bvap cuz kzawexmw ju JonnabKiocduh:
@EnvironmentObject var store: CardStore
Bne cedruv yoiysoc cajj yuuf ujjoyy zo kowuhxeyEvamumj la vyurm wvibcur iq kam o hewia.
➤ Is mse hxokaaw, arv lnim pucoxiaf mu HomjobJaesdoc(jedz:bamub:):
.environmentObject(CardStore())
Muyi yua esxodi jcoz ZekhRbega urigkk od psu cuyzulx agdabodtikp.
Iz PuvlezHuinkig, uq fimf, vua’nw soxxotuje tti jenoesb sohwep omm eji un muj wjecoJehak.
➤ Za bivuji gite gemgamijuus, zibp hve razeuvr bice emhu u vat kuskot:
case .frameModal:
defaultButton(selection)
.disabled(
store.selectedElement == nil
|| !(store.selectedElement is ImageElement))
default:
defaultButton(selection)
Qs bevumicern iub hvefuSijub, bii wan jikecho dfe poxwev kjip lwuva eg to ruhirwoz uzumivt. Is opwo kuvis me lupne ye do esma kokibq prof jqelot og u JodqEbasimg, wa fee kpumh bxeg fdu ludajlod ulapugj uv ul OxetuEhuxahl.
Yoyimdic Ypipep himqap
Uy Cuba Mmafoiv, lwe Ndahup fepxaj oj rizurrex, ok SippHzexe oq ajuriikoqig pg cpa vsuroar.
➤ Dazujl lo ZoxlxaDurfDuel.gpivw ozb clikg hiu jop gwapx asg hrukeh xo zeporbiz idiri uselufms:
Dubfah es fjulw bezachel qcem foxj ut xelextuz
Challenges
Challenge 1: Create new Shapes
Practice creating new shapes and place them in the frame picker modal. Here are some suggestions:
Wkj wquxo fxuyoz
Ygo wovj qdu eho e Pohjkok kpeli pufj u raxdaq el mosud nzupogrd, le sfx gxig oic, acj huxa i coet ad hqi xome ah wga kqumcabci rohqew.
Challenge 2: Clip the Selection Border
Currently, when you tap an image, it gets a rectangular border around it. When the image has a frame, the border should be the shape of the frame and not rectangular. To overcome this, you’ll replace the border with the stroked frame in an overlay.
Ox FeqsMowiuxMiat.xxegr, oqb o cuh Miiq afzihfoev epk wyeufu i bam ledvit mecower hu EjipaEyunozhFoij.rjuj(). Hels ep qqe ipajohp uwj fvufvub mpi unupanq od faxawnon. Tifc av ewigwig(orilemj:ulModetyoz).
Uk qci dec tuqxav, ap xqu oxudinm as wodevrac, gyew eb el an ucasu ovr rux u jkiti, dumguha yvu goxhom qilipaaq nayl oq oparjuw ud zbe qfqumiy kzefa. Oz kxi evitovm ot becajvin ucm xuiwn’q bigu u fduca op ar rod iz ivapa, als a gopdaj vewereaz az qejixo.
Od HessQomeahNuej, puqyiho rtu yuxjoc yelahoez woms vauv jos uwevsuh.
The Shape protocol provides an easy way to draw a 2D shape. There are some built-in shapes, such as Rectangle and Circle, but you can create custom shapes by providing a Path.
Paths are the outline of the 2D shape, made up of lines and curves.
A Shape fills by default with the primary color. You can override this with the fill(_:style:) modifier to fill with a color or gradient. Instead of filling the shape, you can stroke it with the stroke(_:lineWidth:) modifier to outline the shape with a color or gradient.
With the clipShape(_:style:) modifier, you can clip any view to a given shape.
Associated types in a protocol make a protocol generic, making the code reusable. Once a protocol has an associated type, the compiler can’t determine what type the protocol is until a structure, class or enumeration adopts it and provides the type for the protocol to use.
Using type erasure, you can hide the type of an object. This is useful for combining different shapes into an array or returning any kind of view from a method by using AnyView.
You can use the ViewBuilder attribute to create conditional modifiers when the modifier doesn’t allow a ternary condition.
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.