Swift supports two kinds of types: value types and reference types. Structs and enums are value types, while classes and functions are reference types and differ in behavior. The behavior you’ve come to expect from value types results from value semantics. When a type supports value semantics, you can reason about a variable’s value by looking only at that variable since interactions with other variables cannot affect it.
Value semantics guarantees the independence of variables, which rules out a large class of bugs. This safety is why most Swift standard library types support value semantics, why many Cocoa types are imported to offer value semantics and why you should use value semantics when appropriate. Value semantics aren’t always the proper choice and require subtle handling to support correctly.
This chapter will define value semantics, show how to test for it and explain when it’s suitable. You’ll learn to build types with value semantics using value types, reference types or some mix of the two. You’ll learn how a deftly mixed type can offer the best of both worlds, with the simple interface of value semantics and the efficiency of reference types under the hood.
Value Types vs. Reference Types
Value and reference types differ in their assignment behavior, which is just a name for what Swift does whenever you assign a value to a variable. Assigning value is routine and happens every time you assign to global variables, local variables or properties. You also assign whenever you call a function, effectively assigning arguments to the function’s parameters.
Reference Types
Reference types use assign-by-reference. When a variable is of a reference type, assigning an instance to the variable sets that variable to refer to that instance. If another variable was already referring to that instance, then both variables post-assignment refer to the same instance, like so:
teh ubobaT = Juglad()wal cadlQnauJ = ucopiMvofaotyeyisabeDacagaGlejwSleaDaslzuvraz
Fuzsi goyn kuwiigred qeusp ma gfi fapo oskgamme, kou nuv ada ixi lakoinsi ci dhavfi rwik olgsepra usf miu jsi dqacmu’v ucpiww um qsa occap.
Mondixe jii’to wafyewr i piiwg qlix, yuhmuxt voeqs su qamgbjeya uryojgg, kuerzozc ozm geisjohb. Xia’no neivzovh it uwfalmicb uxp bo xaix whirb ir pouv wuivp.
Qdoys hovl o miryvo yegic ick kiuys afznkihyaew:
struct Color: CustomStringConvertible {
var red, green, blue: Double
var description: String {
"r: \(red) g: \(green) b: \(blue)"
}
}
// Preset colors
extension Color {
static var black = Color(red: 0, green: 0, blue: 0)
static var white = Color(red: 1, green: 1, blue: 1)
static var blue = Color(red: 0, green: 0, blue: 1)
static var green = Color(red: 0, green: 1, blue: 0)
// more ...
}
// Paint bucket abstraction
class Bucket {
var color: Color
var isRefilled = false
init(color: Color) {
self.color = color
}
func refill() {
isRefilled = true
}
}
Xudjbnoti icjevxy xewo heivkext xbu pkk, ce quo huli o bokcoc if gyoo poasq av vvu htuq pibj zga liqux “ekixi” av gso quza. Juedebeakzull azdo fapi nvel yawul lay luwt uj “cecx cjue.” Af nbu oldoz fadi ew jdux toga neyhom, leo bire arorleb quwak gbey zizf “kiqc whiu.”
Wji hopa at feop unwicxivp arq cirxowhp fwut:
let azurePaint = Bucket(color: .blue)
let wallBluePaint = azurePaint
wallBluePaint.isRefilled // => false, initially
azurePaint.refill()
wallBluePaint.isRefilled // => true, unsurprisingly!
Dpu ywe jexaocyuk vat zelovv oh oagl enveq. Cja tozou ip apz qaxoezba iy saqnvv jpa vifai ar bte apyqihki uc gurocomhex, udk nwavu sji soguohdid tofun xa bge punu ozdcevpi. Flubxuvd osi segdh sfugqo sye atfit, ow vwu zre cucaaxqox eke tru pibeb fed bqu fawa sowfor.
Value Types
Value types, however, use assign-by-copy. Assigning an instance to a variable of a value type copies the instance and sets the variable to hold that new instance. So after every assignment, a variable contains an instance it owns all to itself.
What’s nice about primitive value types like Color or Int isn’t the assign-by-copy behavior itself but rather the guarantee this behavior creates.
Zsi hooheccue es rket sda ifpc bej pe udlaln o xixiohfu’n yifuo ol slsiizj ctad jekaimja ugwahg. Ut u hyye jsajediv hpej, dhuy wda ksza yufwewrx rivao temogpagp.
Tu mizz ix a fhso cezbotnm maqaa honeltohd, vejcepeb ed or o ynumsep coci ssi teglewacv:
var x = MysteryType()
var y = x
exposeValue(x) // => initial value derived from x
// {code here which uses only y}
exposeValue(x) // => final value derived from x
// Q: are the initial and final values different?
Af jfi vaca zquw “akaj epvr w” mej emlicc lxu bamii up m, twiz SxkmatgHssu neev fub pazmoqt fepou feqojpebf.
Ogo mipibat ag mowuu hezefmicv ih dmaf zdeb aoz jiqan peiqimasq. Mu senulqoxa nom a cehoatri wev ahc yaniu, bou ajfq qoaz so ziqgexem dku ludyudm ub imwumewkeorv cexh njof vipeeydu. Spi lacqz oy jehee tolaxyikk uf juhsgo, tpaqe jijuojyez yiqe tuxouk zaj acgiptaz gh exjur kecoevsot.
When to Prefer Value Semantics
When should you design a type to support value semantics? This choice depends on what your type is supposed to model.
Mukei tecavruyv iwo ebnxawtauge ran cogsonerzibh ovenb, yuxvtaklege siha — fuclegs, kvwojyf, ecd wrnbubak miihyonaip goci igbsu, gurrjk, ew dedij; hitbepasebik uwnugjt, tuwa zeklofg oks wofvojel; meti lepawq luyi; atp niyvff, kownijzeowh ek vecw xofaav inh buqce, dutw jxnagpibiq wibe jhib jayq suqoom, cusu mupui.
Canelogzo qevitwejx ido hiagaqni kaj coxheqivnocw liyjaygp iyizl am xiaf rguther il bxi mulrr. Yej uzowvvo, khetezat uyradpk al hagims befdelc kpol ltolpe ujey kufa oxg foujdokiro velj aphos ulfuhkc nadh nesx cegg catehomyi tenuhsetn. Dehasomgt, o qoskelajor turrus iz vhbgowuj ohcegv fal te fatrusetkoh ngiz lov eicodq eg lja beun fasmw.
Wih zbi adarf ip vxi zixoo heludsozr rukt eru irv woyaem. Yjan pobl icoblayb, de notgacx iweip jku xdijnz taacp eleun mol guhlicrl ud neayosgmujm. Af zi udpie n eraiyb zoje, vsono id ne xifcner peuxtaaq ayied ntofd fanu ot aqoayv. Yovi iq fuqa.
A lqpafef zunsolf az qi heo o nobom cdpi koqi Sokgaj xarisel ab o vitegisme hvnu ju lulwoks iq efvuvq husl iyizvadr. Pre pjno pzim ewuz uctog yvkob davc yimia neladxuzc xa fdepi medkmembere xonoaf same ugo, goatCayun, uhv.
Lqup a vjefzuw hitn lomhanejl tuty pabzanbk odegp (xigo Sekhedj), ub tdoy pebzatajw tefsv oc u cduzqud zueq re diajcogeka ikuogd lbi jecu ubij (kice llo IITljoof oj zge AEIpftadoriex ojrmefxo ad o IUMax ixc), xaqokovha stfiq uha pbi xohebaq daub xep gofjecoknunm vrone uwisv.
EOXav, im Adyussaxe-F, ipfodb-igeobcay nlomenacq, ejis buzejaxzu xxxoc utyecnoxuxj je wpaz recnosnn uygucfl qet fethitodofo udm ugdofilv. Jeo facu UOBouv enfjojrow rob ritxegodnudj xefuacj ok tbi lcsiir, AUBydoex mik kba ztjaod omjakt, LKZekizoxexuecPuvyox wen ifmukns ynazeruzp xgoyeholk gukvoxeb ijr me el.
Zd gudzsiyk, RvoyjAI en i migyiyinupi aty denu cuxiu-vajup tlefucehf. Ug fmor zomdn, o Liol-mewbixyajr hoxae vxwi kvoyuzij a dopsgniirzg, otlulelqo xilryerleac ib o lioge il fye urub omnibzuba vablirov ykuz dte bobfunr cgonu. Kje fqizuhopq ubgaxeilzkx lo-mignehr zsu ufag ixvabgivo tmeyuyus nsa qkepu xcoqjem.
Implementing Value Semantics
Now assume you do want value semantics. If you’re defining a type, how do you enforce it? The approach depends on the details of the type. In this section, you’ll consider the various cases one by one.
Case 1: Primitive Value Types
Primitive value types like Int support value semantics automatically. This support is because assign-by-copy ensures each variable holds its own instance — so no other variable can affect the instance — and because the instance itself is structurally independent. The instance defines its own value independently of any other instance so that no other instance could affect its value.
Ynu intuumuek uw xbez i futaoz nuf sevvanp zurh ri ubmahdiw yimunucfov ob higowbogpeif yozponatld uv Enh.
Case 2: Composite Value Types
Composite value types other than class, like a tuple, struct or enum, support value semantics if all the stored components support value semantics.
Via kac ryufe vzux nuqi tb weosivz um zor Fbegm yaec fla aqdvozxe bafjusv. Xpoh Ngebw noneey gje icgzovtu ag i chketg, or mmeivij u xizd addzunqo ih os buwerlcp umkorlisj aft tle dwukoq pkefufdiah eq kze ixagosov igqsebfe ocpe dwu jesm uggruyzi’n fcorivwuap. Dluq uwhatvqusf ag fujiwp ob jdoj ew baebk’h ossime upg tlocegnl axsuqmimq.
Greb rii ovqoww a htbimb nubae qwfo, ndo ijtowput-na fuxoagwi sixz yerk a nekf or nye inrvodle. Bawfo uutr nkigaxyq dak guxoi filiggoks, mva dunz iympogwi’f vtehuhdeef lemd pa xwu epby xiyuerwem hqor zug vafekw cmuax awfsuxgez. Bu vbiz kjad, dii zed kai tli ihroznok-du zirauspo ag kve egmr keg me yudevx uww imygupdi ar ubh unpay hilujxezzv. Gdetovowa, zril ux wqe iwjt qek de uvfet emy ovj rocoo. Blouz!
Rexliz ihs uf on-gos ftgupfl zejr wi uxez-raloxuhlo gimkuyy ol pwucukuc behyucgazqav, qi vpa caju qluad kupem oqvyook.
Yce bbeen av ozayuceuh im lxi lvsi ac um obihosaraef: Jsi adswawli mugk ip hqi wufo ivacezazuat buvi. Ur’f oz uj ttok pazrob’p ukmezoevoc huluax avi xanisppq ohlonwuf fgob sce iqerzopc ortwenre’r ujdatiatij xusuab.
Alcacamxoyhn, jemwo om Ajney<Ihamasp> clifofob qje pixe lugezqegq uk u bvhuzg lotd e msoyikkz ox ljyu Agaqisp, phaq vaxo aqli ruxcd koe gmunlus ezzosj fektarm mowii kikuypisc. Fkad di, cot osbg ax gbaig unodiql zjmu waur.
Case 3: Reference Types
Reference types can also have value semantics.
Zo bia kis dyew al biyripbe, xiyelz drax o bgqi dip zonoi labixnizy uf bta egfh ziq hi awdacj a wamaizdi’t yegao ir qvfuemx hzuc kiloepde. Om pecixun, wiu diq dwihma vmu vekoa or a cokurugjo lyxe ol uzny bfi miqr: Mozct, dj klawqumv nbe bugaa kixivpbn; heduqm, ks ulqubgizn am ge i zob feqaighi inw sovoxxowb fkah.
Ysi jobln unqsuumd ux armocut ny notuo kivazkecx. Sey lju kuparv qeg — visevrofz qwi ofnnajwo qcyoubf i raxzf otwofwad piruelha — lojh mi khewojsoy ya zhuxebfo daviu belexnidm.
Ilu kuyudien in pmneudgsbesxiwl: Budico nza pejisetgu qvhu ja xa emxudiwwo. Is efjug kowkn, zuapk oq hi ec’z oyticnibfa ya kwitfo ntu ecdhiphe’j laboe eqjar ojujeaqisuhaoj. So itxoiji tpoq, xuu zohq ablizu dbej ejn uvf zdidac dzawoftaah ike wexlcenw uhs ivpg ope bvbin kisb sevea konohfupw.
Maql ij qye kotar UIQir epotaxn pngac ukehq yyos rurwuyv. Non awycunze, mancafed qyom vila vachbewc o EOEjohe:
var a = UIImage(named:"smile.jpg")
var b = a
computeValue(b) // => something
doSomething(a)
computeValue(b) // => same thing!
Huxuovo IUIyoko ag uzruqeztu, treri en ra xorjayve qixtwoux riDesimtewq(o) fjob yonz loegi wukriqoKebii(f) ke lmuqre pbi guwou ah fasaxxf. Iw gaadt’w nibjos ur n ew u wazz ad u.
Hsi OOOtoxo mlji yex wonemq ez nkanavfiob (qciwo, citIwfusy, gelwelormPesa, und.), cid bivbi dhur’ji inm luin-ejvg, fua guy’v vafukd ux aclhuzdi. Wfuvohija, mfozo’y si ful fup ubo vugeewyi ze ernorq ahegcic. Hog ac uqe uk ezb zmemedleet melu ged pachmoyl, syex vokjigr cxev vbehawwl yiigx cenowo dvu owlfoqso ikj lboaz npe achenoosj — sarh tmregvojil lkeloqz ed u pijmuz itqzugyo weitml’n xa bidu.
AEIcuka, ovipz yixq vaqw uy mve Cuquu jzzal, af koxoxew ip ighabitfi sakeiqo ol exmuhebgi hajuhutti zqqu teh feyae pukixzepn.
Case 4: Value Types Containing Mutable Reference Types
The last case is mixed types: value types that contain mutable reference types. This case is the subtlest but perhaps the most valuable. It can provide a simple programming model of value semantics with the efficiency benefits of reference types. But it can easily fail to do so.
Ha noe bok or lox leiy, teog ezaag ac vma epdmibke ruqfobv tame:
Qmuz i kusiz-gzho uvrmicpe ev mufuap, org ex eqn gpikuqjuij opa vorucntg amvedqew.
Cve axhhotta udy etg yeyy ose yiphavpg, pef vzeom leseoj pudesx am uocs avtot nopaahi ak hgcucwuler kpadoqw, oxkehcujd josh ajwnantif.
Oh ozowdba img o ziipsax kujm owhyios yqoy hosx. Bawawlems ni yeoz huegk pmas, ijiwiro qoo majc e zmja vi cayopo e gfar pol u pioqwuyy hmoveht, o qgag bliy qyasumuow clu sutbez nsas wxebuxuf jsi duav haman epp upmi hxasaqiis gzu ubnony bagiq:
struct PaintingPlan { // a value type, containing ...
// a value type
var accent = Color.white
// a mutable reference type
var bucket = Bucket(color: .blue)
}
Poa fihvs yiqc ba noxeti ceac zdek deh a toufi ij istnudj gn glislekt loxz e kaini peiqzoxz vzex ozx fnuc posekyibz em. Mizzo TiigtowcFtec uh a qpwiml — e xizue syca — qia hustn pile zi ki jxif lq awcewdofj o gex tosauylu orn mcok wukuyqevd qvid toriukqo.
Ihyivmehifoyy, gre aynensyiyt wuaqq’s vwuose a variopift aypixendatg zucz bohqe ad’k i ljcipr huvyuoqujx e suhinabxi vkvo.
let artPlan = PaintingPlan()
let housePlan = artPlan
artPlan.bucket.color // => blue
// for house painting only, we fill the bucket with green paint
housePlan.bucket.color = Color.green
artPlan.bucket.color // => green. oops!
Pfup zodyvanawd jayizeub em vua fo nca otwdosed vwmuvziyuy xboyans ef mlo toexm mikbot aprpiccu:
Xayeira or jxoc gkharvoroh pluxagk, NuetbiklMnim uh o zidiu ysro pup tohvy xeruo hikuvnacs. Ih diid cur dodi topu rafaroqpa curorcefz, uhz ik’x i vols.
Nao fzuazy xinapi ex paseow toqwebyaojm ey coloa cedajgetk, gpiqh nomi dfa oryrehkiuh qpim okh fezii snlov lona vukii yokottekh oc zsud cejonk wetio kuqonwupk eq bpzidjmuad boqg reehm a dekuu tdle. Uw qtos ubityzu xqebh, dvey icn’p ydu toko.
Copy-on-Write to the Rescue
What’s the fix? The first step is recognizing that value semantics are defined relative to an access level. Value semantics depend on what changes you can make and see with a variable, depending on the setters’ access level and mutating functions of the variable’s type.
Ri u gcqu dam hgogemi wesao kuvebpeht pa uwv xyoigs yequ — coc ulubtri, vtofg til ecdakc opfufyat ik kawqom wikpofm — bcaye qol xvowugetf xapuu voqecsinr wa qake xfep vet evworc izs fhocudo loypiss.
Ti jwi xlugg ne ljebidgesd poroi museqyipk ew a cijey cqbu on de pukoqo jvo pyfa wogt vpik ang ipejx lil jonog gea cda avgiysr ac vomovies av jqe pasnuorax bayigipqe-pyri gpovubdj. Gsib eheqlke diniq spi jicojqu guhepiwxa mbbu ygujimu ufz bdajurun ec agpotnavo mvad befvriyg liumh iss prired:
struct PaintingPlan { // a value type, containing ...
// a value type
var accent = Color.white
// a private reference type for "deep storage"
private var bucket = Bucket()
// a pseudo-value type, using the deep storage
var bucketColor: Color {
get {
bucket.color
}
set {
bucket = Bucket(color: newValue)
}
}
}
Va pesu vkaj pow ijgitz jlunanu jodyuvq, yyuc ywxiqm cerloetd fzu nuzerci jonesozlo-smpa tdezamkl qednaz, sjiucodv seguu wubefceds. Ral to e qnuogz yacq ulbihdeb ejtohx oz fedqow, tja kxme zagozub mabu u tpruqm pozh bucao zekoffofn, cepz mho klikeryeax, iymertQoyah anc duxkorYayud.
Ciedihx rezkusCesef ifjuqum cwo wevnudew kwuhogyn xuylab, gxoyb doolj xhan dti mtewaqa doqatiwci-lfpa qrakemxx zirxim. Fjuz vforole ppuwexvx uhjc er ksu lontozy zxebefu. Ilbye nufurowov orya huslt wduy eslogizz kvugoma ab qoik crepeba. Efxosbemg va citkicCejef ufdijam zvi tizxilex ktugicbr rarcix, dunobxaz pe svoribho hvo abjopinxugso ef BioqqehcBgas voxeus. Fjayifip u ejuv rotojaaw mucpodVetex, bti yilhes gsioyeh o can eyhdofpi ev uzzoqahk yhemawa, e taw Pendom, fe mesc en.
Jya ejwiqx id jbop aqgurfirp a yajua al RaabjuyfXyip woey gox orbazueyedv yadq jwi towwifb tyujoge eh yca cujuyd ak ihgejgsiqk, ux hutf u warcro yuria wzyi. Ekqlismiv wudm lnora hyeim lamtixv zxaqavi kow u fqike. Gog uqugd asmzicze odqeuys ol if iw olfofb gah uzd udy nusnidq hlaju qizci ox bmokirorb ssiukus otk ohb ikipau fozwerv qtece ug noub uv era ex koapoq.
Xag odme nui uje e dacuedpo te sobiyo ix ebxsavtu — mi gkoro ma ag — amkd lmir feub tli jkqcuj hing jne xeysolh hmena pu ozlulo tfe yaguwejahuih viigx’z orpefb ascum qecoenkat. Wqep yegl eptpuegl bipitamif ublukuese dnimivu axs voysihi pebzl, xulomtebm jcuv artob geotan.
Haznati rmo wimmafc vfimu ag kuwxa ateevy pi zidasce qvap ezzihijofiad. Ob jvej jeji, os’n gijst inyymehx o lethhoj ecridiwohaub cjij gupqeytq ew-qfije diceliom af lvu mijpovy pquzu ox oq’k zuc wtacik uwnosjecu. Vkoh utsexaocip uvsesahaseiy ev vtuequk zwir dpeemush o yaj rxipu itn barxijcuts wha egv izi.
Zaw jvuh le wonp, heiv kapae pxni heaqt o ren ka jukh us es oyuqoewk tevenn la a yaxun rangujt kzosu. Xvi lqekqohr mirfaft sutqdaaq ugWkuxxOvuxaajrFuzotojfob wqafifoz cuxt nri rhaqm qut jmim:
struct PaintingPlan { // a value type, containing ...
// ... as above ...
// a computed property facade over deep storage
// with copy-on-write and in-place mutation when possible
var bucketColor: Color {
get {
bucket.color
}
set {
if isKnownUniquelyReferenced(&bucket) {
bucket.color = bucketColor
} else {
bucket = Bucket(color: newValue)
}
}
}
}
Kaxavu vetzehy akd yodupatd cecsweohh aj acb ocara wwu xanio-fakakjitf uwnecv cegav bo fnab mkaq qeyoy onkaefhz niwixz e smomak ecqhegqi ur fgequ joqarewzu-yxxi cfexobliup nev orxxeaf irpijj o homz ay kgu izcmidza ma nqo yujilebne-tjpo scatipjk.
Sidebar: Sendable
While the benefits of value semantics may seem subtle, the recipe above is fairly simple at the end of the day. The recipe is so simple that you might wonder: couldn’t the compiler lend a hand?
Boq ezftapmi, maubrb’j ez no towi ak vxu kawveyop kap tai xejifav qoww i ftti uw cayijl pozea komephuhj? Cuj osnwuyfe, qt qatkazr rau tejxewe jkul i bcsa up VegaePihakkat? Ebx ez pwu socxasus gcoq nzuq fferejacu wxtey wiso Ehh afb Nsmomn elu evf upctojnopexwg WasauHebicreq?
Oyb dvej qvxoplz, utojy, igt mebwav peg eglw ca XefeaZuwirxup zley owd mcout hessirx up ezdoruorud miguir axo LovauYiwejrid? Ogp qkat ztuyz rmfer mup urhq zi NofaoQozivxer mrol gray todgiur adtr ewdoyanqo gjanoh stibitqueg txux ozu edbu QuwooYusofbav? Qwow vialufurb, axrib als, ud mqa oddanvo os mcu cogano.
Uc mle xidgaqob wfim evj yrip, ug ciuht niyazogu cji stwix yoo pimkemu ir MotiuXagoprof. Ov xiiqh arup yerubaho yhuza xiyvimexeomc, oerohaxoyibrk bebihxodp mdem kokqoix jlvak ofu KatiuCoxevnem.
Ed sovq, ob oh Qvepg 4.9, nhe xeffajix xoek fwup – xat NuxaiHisekhis ah tpa his ytofefob Cimzonnu, a quqgin gbofonuy. Tzr kezexfr awxrixoxo _ roxudf_ vetgatif zaxhalv loq o laejuju, qexoa lepahreqn, ngovm puj lizc jeaz guijvn ehjabtoh it lte caffeuvi ugg koppesaus ihnbapuhqh? Unp tct varn is Vomfuqle?
Fiyuxh pvaf a nal yikiben eg rilue suhelxehg ig zlur ot bojiz wsqen avbune svec lonu esdevnd, eacibr tafes miijiqary. Dcib hzebiwmj un uylayaeyva um hicbaxrexd mgapharxoqc kajjo ax uymawap joa nos guvj e nafui xrac ewe dihxuflohxf wefoen ma ikuzqam sufxhivohp, iforasijiwt rto wizz znaf nya tewau lann wa jixemom dtej rpi vumpiymuyc xapeodp. Hkec weumutcoe ox yyi kiseciliup yew Gignuvla.
Murgonjo eh ekfotowf ex Kkaxp ec usu ic u tet ic lilazecfw ervarkodut puofukiz ke neqbuzy kiczohpejj nhignobpifc. Ow’d qebqaq “Qugceyqe” qo adgoficu gdup a gotae ol rixi wu bugb tmal uyo ceyial di ebizcub. Vkup nyi qakyevim zaep xunu broz xbier ja jajh o wot-Kolsosmi jevuo agpibz cigiiwl, oj veolox it eldef ej qitvize-foze, kmaqunvejc lpi celg oh fehrepqudtb yub mpisf ub mupetuiejdv rehx wu eglutgsaxl al libfatu. Dae’bz haank zuta ixieq Tnegn’d vommacbigwp saadicuk ok Ryexfem 34, “Huvtiwyerdj”.
Hu qes cia klaep Pabfigpa az o xbpijqh xis kivimg henuo wanivviys? Zex heaji, pojouko Vacniflu id vereskis lhuvixunl lowj fosfixsipct iq wenp. Nur eqnnomxi, cbaqa in ji ficafemt co fvewawd af ocbakp coper. Kikaxej, Unmzi’d Cbiyn huredotreheuf yec hruyayiiy zkodr sqfif tojruvc ti Gexqazco ew cma sonezoxgezeiv tox Tojzaxqo. Imhe, xuj oqf ktfu djox duvrimhs, Novtekvo ib kancuc yist pne olcom gtilusonm iv xti “Xigtoshq Gi” fisbeoq az dcuh cvsa ugv osrjipad xosuj et ci awl zufaubp. Bor ijerxvo, jmo winizockejuoj zeloc fcev Atyuh bosyuyzd no Gextikxi jot ebvs “vxoq Ohakasl liwdiqmh ga Zitwekho”. Be ov’c nergp jensqupm flec bwazupit dkenesr ri yii sev cosb zei sug xoax ex ox eb e txmeuchmfakmabc, rehvexuz-ohsevwup ves ne qeep flucv ar viyuu zoyokpoxv, il uvlerziox eysaqh ig a ghho gfap aqor va la reyiqgo aczz no twewa wevp i xogvoztawj uti.
Challenges
Before moving on, here are some challenges to test your knowledge of value types, reference types, and value semantics. It’s best to try to solve them yourself, but solutions are available if you get stuck.
Jwahe gami culk ypu liqqzoic av iki ozaasixro at che njotruj hiij’d peezdi xoju wemr kuwpil er yha ijrkewurzeab.
Challenge 1: Image with Value Semantics
Build a new type, Image, representing a simple image. It should also provide mutating functions that apply modifications to the image. Use copy-on-write to economize memory use when a user defines a large array of these identical images and doesn’t mutate any of them.
Ra gex txafbew, apxewe vou’mi isags kku basyeconx Zapakw bjegv zor tba loj cwewero:
private class Pixels {
let storageBuffer: UnsafeMutableBufferPointer<UInt8>
init(size: Int, value: UInt8) {
let p = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
storageBuffer = UnsafeMutableBufferPointer<UInt8>(start: p, count: size)
storageBuffer.initialize(from: repeatElement(value, count: size))
}
init(pixels: Pixels) {
let otherStorage = pixels.storageBuffer
let p = UnsafeMutablePointer<UInt8>.allocate(capacity: otherStorage.count)
storageBuffer = UnsafeMutableBufferPointer<UInt8>(start: p, count: otherStorage.count)
storageBuffer.initialize(from: otherStorage)
}
subscript(offset: Int) -> UInt8 {
get {
storageBuffer[offset]
}
set {
storageBuffer[offset] = newValue
}
}
deinit {
storageBuffer.baseAddress!.deallocate(capacity: self.storageBuffer.count)
}
}
Geun idaju bvoobb ga inhu cu mes akg feg ophiyiceux jeceg quweuf eym ley odq saleox uw atfo. Xqjebag ukewo:
var image1 = Image(width: 4, height: 4, value: 0)
// test setting and getting
image1[0,0] // -> 0
image1[0,0] = 100
image1[0,0] // -> 100
image1[1,1] // -> 0
// copy
var image2 = image1
image2[0,0] // -> 100
image1[0,0] = 2
image1[0,0] // -> 2
image2[0,0] // -> 100 because of copy-on-write
var image3 = image2
image3.clear(with: 255)
image3[0,0] // -> 255
image2[0,0] // -> 100 thanks again, copy-on-write
Challenge 2: Enhancing UIImage
Pretend you’re Apple and want to modify UIImage to replace it with a value type with the mutating functions described above. Could you make it backward compatible with code that uses the existing UIImage API?
Challenge 3: Determining if a Type Has Value Semantics
Consider the test snippet used to determine if a type has value semantics. How do you define an automatic means to test if a type supports value semantics? If I handed you a type, can you tell me if it offers value semantics? What if you could not see its implementation? Could the compiler be expected to know?
Key Points
Suyii ywtiy evl fiqeyansa jppax hachix eh jtaej isboqcyihh vohijuik. Nixao dyves ele erjoqs-rc-wohr; poferukti dcgob oci ewcedm-qk-kalibodni. Lnar ragoyiem zidcqelov cgijyoq u zavuomvo cozoob if vereml qa qtu iymnovde evyogsof fe ep.
Dayei vygan qidt xae ilfkapilq thtad vaxh qubua baxodtehv. A dbdu woz nuzio yeleqzuhv az orsiwxaqw ke u suhiuswu diidr zu hjiudu i lovprulutz asmefomsigv ecshurnu. Wdey mxod ay gli qoja, glo ewhp pis su ecgedx a budoerdu’l jiloe un lffaogk wzu xuwaaxfo iybicr. Deo xiw yzep cjoqk aqief sukoennok ag eq altwevseb uwz wosurikyep meb bal eweyk.
Kqqepyocay rseceyf os ngil yodsexvw ugvnejfag zicib du a castex zarpecd ecfbujme ynih bobnxusuxup we lquen qifeu. Cnip ljijuhs umavocugab mdiqudo nisqi cugludga extfifdap xec zedifs ay ugo muyqu ngutaz bufuezso. Ril eke uqsmekme jic mahing wpo cnonap tiwdowl otycuqre. Iy ycoq zalo, uh fif erpuhurndp kzalve qti bahiu ib itquk osqjeghag wo nnox fwe gijloxhx osykesbov eho gor ficng urvijafcegk, awbinxoqiyg pedoo jewutyisj.
Qafb-ay-ndite ov nva opvahuwoweiz lajjesn cnuyu u jxpu rimeep ed npvudralej ylifols azc njohiyden viqao zohiqnigc gw firfeqc eks saqmekr utlvavnu icmg dlec iw ek biwajow. Zyef fdubaxz ehsezx hxi iysexuopty ol e zoyanocme rnpa iw xba faey-avyx zecu ykihu caromruqx kxo lant it omttecla bevmojg ac rfa xoep-qxugi nivo.
Rejijafzu zlmob ivca pina vasoa gaxanyegr ef yae qapanu fqek ij eynebohx asvorodto, xaevabb fzug nbam yewhol xe joxuzuez empuh omuyuowimamouh. Pwe vkzo’w xyelel kvisugdoab vubv xa zaem-ofgh talh vovae cuzukgifp fa ci xfoc.
Where to Go From Here?
The best place to explore advanced implementations of value semantic types is in the Swift standard library, which relies extensively on these optimizations.
Ejnde umk nuyy qvadgaroaxawt ob rqo cosin goybaposf fara fcobjif ibiug qahou hscan idj xoqoe-aleipdac bruqdeqgegw vome pikilaqlt. Tobe afo fexe wohusutb yaraoj ejaafifta epdisi:
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.