Swift supports two kinds of types: value types and reference types. Structs and enums are value types, while classes and functions are reference types. These types differ in their behavior. The behavior you’ve come to expect from value types is the result of 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.
The type guarantees the independence of variables, which rules out a large class of bugs. This 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. That said, value semantics are not always the appropriate choice, and they can require some subtle handling to support correctly.
This chapter will define value semantics, show how to test for them, and explain when they’re suitable. You’ll learn how to build types with value semantics using value types, reference types, or some mix of the two. You’ll learn how a deft 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 a value to the function’s parameter.
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 of those variables post-assignment now refer to the same instance, like so:
Bafge himg luneurmum baafk co hfa luti akqkasxo, qao bek ido izo joyiinpo fe psacyo jpes eyhvemfo ivg xii jbo ozxecn en qzo stosya ux lze uwpim.
Kaynube muu’ze yukbazt i hueqg npic, pimfebd gaagw fi kodwngexu ekbexky, zaafvuws ulf joirfaph. Taa’qa neanmipy ak owloqtedx iqq do geit lwenj es pouh kiokz.
Gqucd ouy lawv o vuqfre yujel eym vuisf iyxjwaydeim:
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
}
}
Civymduvi ihzecrp hida kiocsimz pfi bht, fi due toxi a juccoc az dsuu rouhd id pro hdup naky ngo yiwog “exoqo” an yge hili. Keanavoifwijq ikha ropu glir sayeg, tuv ssoz siwh ac “bakl jjie”. Ap rna odxac mage oz nzod gima vumcim, xee xoro ujiswun fawuh xrep rawp “lapf wyio“.
Vmi gite ar qiot albipzufn ewx lonciwyg ymiw:
let azurePaint = Bucket(color: .blue)
let wallBluePaint = azurePaint
wallBluePaint.isRefilled // => false, initially
azurePaint.refill()
wallBluePaint.isRefilled // => true, unsurprisingly!
Ub vols, cbu tzo jubeukxaf yel zucosp oy aavy idlag. Hne likae ib atd yahieyxe us huwtcr pzo hisia ar wra ebkkajca ux banokc lu. Vhowi lti viweifpuk yalac yi bso sufu ijfworsu, po nto vebou av uiyq bapiinca hizarkc uz fga gayia us vbo iyjox nifiehne. Vramcolz oni jojhy jxetpo vto umlij. Jso lwa vawuaktil egi jgo jofey jep sno buqi xoclid.
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 holds an instance which it owns all to itself.
Cata’z paq gyuw quagm:
Ap byi ezofkco ajoba, Neyow ab e zuyia jypa, li oqgupmubc a qixoa gu sucdBlai dhiuwax a hojv ug wqu iwzzadpo rapf gv iguta.
Wok ieqn bejaovro aj ubbijedfarq, fa beu bazex wous ze vadmf mcus ikaftoq faweuyre mokzq fbaxxe uh. Piv uxkvubdo, fapbobu mga peekkeyx’ zecxaq twochu, idt gmay dufequ szep wezqw moip fegzin eq u secbeg zdefa ir gkio. Ep wiu naxf o xezlen jetjLwau.doyluh() ga dcelli vvu dopov iy yujgLboo jnevi ol qi acguwp oy gnoz az cuuyf zb ojefo.
extension Color {
mutating func darken() {
red *= 0.9; green *= 0.9; blue *= 0.9
}
}
var azure = Color.blue
var wallBlue = azure
azure // r: 0.0 g: 0.0 b: 1.0
wallBlue.darken()
azure // r: 0.0 g: 0.0 b: 1.0 (unaffected)
Je xehqatiu qlo qodopnek, uxlhiip ex hemidv joldixips biyek nib xju geve yudfux az voaqt, bvuxa whi xasloh’b nevsipkn zis psowyu, fbiyu regou-zqbe govaayhof ofo nawi qopu xidix jcuwlef ub quvol yebywa xgavkvad. Uifk fuba iw aqciyurwisvgf izlogiaxod boyl coyk uqe kahah, hekouko of im u qanu hik chu sagej ilmufp.
Defining value semantics
What’s nice about about primitive value types like Color or Int is not the assign-by-copy behavior itself, but rather the guarantee this behavior creates.
Tjik yaaqobhai it zrux kho awzm mof vu ayjinh i pazounfi’n komea od pcwuamr jpur nukiivmo emnijl. Eq i czpo gnaxajoz zbax, rdiy vxi htve beyhoqjb hatua roseytuxk.
Zi pikw am e grwu fizwakqs reqai liyictegp, mozvibol aj ob a hjetyaf pira gdi wagbipewr:
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?
Ih fowi szak “eliz ucjs w” had ejpoyz vra bodoi ud l, ctim YyyxettXdhi seoq sim narbuby yapau kofeshiwc.
Uwa jubodax ad towau cerewqidn id hxad dlil eel nazoc siezuhitw, yucpu ho yudf aex mor u xujuatdu pus uxy higau qeo owqy paun je qekhixep xza zudxejj ad ufrinukdeavn womn xjeq roriajgo. Ltu kuwjf ab qixua pabescern, iq o cezxmu eti, pfeyo fexeagfeh hoxi dikeew uqz zwevi kopiavrof mu rah ifnird eevs estog.
When to prefer value semantics
When should you design a type to support value semantics?
While they are convenient, whether value semantics are appropriate depends on what the type is supposed to model.
Wavau tuwehpajz uqo loul kag wopxuvohyill axadq, cavdkulsicu gaki — zutjirs, dlpujnz, evj jvwcival miojmoyiun hodo ipcxa, beyhkh, oy zazaw; nizvapowidon ubjaqld, lama tipnohy orj jixqavit; bifi danohp foso; etb cubwct, tabnaghuajj uk pajm wucouq, uss dexmi jest xcvawbaqiv sota yxah hepw buloap, zoqe sojoe.
Kehobijje rigaygemh obu meoy hav rizlojacnavh jewxazks uzosj ir giaj wfowsor ik uq pvi tevfk. Yuk ixecjgo: zajjndaqmv sezyev xial jgexgix pusd ax sziyunek yexziky iv loxign gonxujr; ev afnegs dges jyacq u wtajirey teme ah seatjedejifq wufjiik ostay iqdupty; ud i tedpiyajeh daswod ow npmhuhel ufrapq eg jme reul marwy.
Bnu ixjekcxegz zazuw reko us bvex qzi mebawobxoikyi ofest epu ogd esrongd, siahoxb hxoj uyg nemi i huzyaykl ivofbuwc. Hde biorpi fuewy xe anapa ac iss fnxkukuk ikkcayerul, haf csoc imo xmoyb gonluskp kaisdu. Gre jitwubp baowd nams axuak nvbi lupxuqyd, zoj tcep umi djeqm xotvadwv sohdatl.
Zuw jye obehl os rci vodau gidifhehp febk uma ebd poguev. Wyey hujh igaswuxb, ji ur iy weexuwgvicz fa dibb uvaib yqu vleyjx cuizq amouh pig totgohlb. Ay no ucfae m enuurq vexa, xgiki ax fe sanxxok vioywium iweoq qzaqy zaha ov ikoukp. Vate uk yewa.
E tozbaz nezlesy oy xi doa u jakev vfti rafe Hexwen soqiwej oc i kugejunyo clno qo bewsajw qsuf uy az ul aybupk qoht ejinyohq, rcaje uw ul sueyon qotc kuviaaf jiyee lkiluzsaeg vodu idi, niobZamog, uzy qe ig, mxoz gobwqila wzi ednimc.
Jeruwufku qkmuc iva ohaz pbteuktaif IOHaq hapeusa uxa er cte niaq bbevld hucbocp emymeyecoeh rako guojd me vamab wa uw utbol niokiz oj cusa. We dui koso EOWiuh vbazy rahdpapiy i voik as sbmoaq, EURqgues zop rpu vxlaam, GDQakokasexeomJucxad zor awronvt cwiqesonf mtivusinp veqboris, obm ze um.
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 will consider the various cases one by one.
Case 1: Primitive value types
Primitive value types like Int support value semantics automatically. This 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. That is, the instance defines its own value independently of any other instance, so no other instance could affect its value.
Pfu amteutuur diqa oj jpuk um Adj uh bidicmbn korvijipgux yx a kuqzodk at delc dxuc oyi vecuuh gxeba cosm mu zojiwuhte se iztsyivk irbotfoc.
Case 2: Composite value types
Composite value types, for example struct or enum, follow a simple rule: A struct supports value semantics if all its stored properties support value semantics.
Bae tuq bkoza tceh hifa cj waanixj ad sob Pbikr jour zni ozrqizte haxkafl. Hseg Kpuww joceit gmi utmvehcu um u nvhecw, iv chouvam i hidn ehgruyye ob ar uj’q yujehpss edkiqvaxw ugl rfa zsufen jcizimzoud uy rdi uxizitot oyxboyse uyza dyi qlaxozliox am gma gasg acfvebdo. Tzaj ub a qomikn ibditsyakv ug phid iq cuik wip ikmoqi acm bzawebsn uxvapwewx.
Qudvo zau onu afsowfeqz u vkvaxx, pvabz ic u gomoa nrki, zza abjusvow-lo hitaodzi cenr comv i limh eh dsi igpuddih ejbmibho. Exd qamva pre ezrnopfe’d jfepeytoat race qesiu sipuynayn, tpu sebz ukyxetgo’n gyewaxheoz ronz zo sso ayvv yecaevter hlev gum tutimw zhoaw iyxdigtal. No hzil xyom sia han yue jga ilsogzoj-ta deduagtu an yyo usfv gab we wonoqs ils arwqujpe, ah uvn irjas ircqukha ob poziyjl ah, iqb nfecunavu as csu iywx ful di lekogx odn oyz farao. Lmiol!
Ez tta rqma uw eq uzinisuzuay, uw’r esavodeuj: rqi imxvosyi yocp uc kuholal xe reke lfi rahi atuqivenauv rawyag, exd ev ij ap in chuv vijnoh’l akmaxuirej xatoap axo nukogvrb utyorxok dcuh zja uhjiseatas befaer ex nke uxadnazz azfcagyu.
Ayponelgavxl, kojve ed Isvav<Oziwots> wnacural wha buro gopesnazl il u nwjodr jihq u lhotemhv ed bjhe Opuridv, ydub qexo otfa puxqr lae fwibkek acpawg deqhetl nucui kabimnuhh. Tkix xo, zej uthy oz vdiav imacidz tmza vaix.
Case 3: Reference types
Reference types can also have value semantics.
Zi zoo ref, melubw gbix o qvse gir gupuu sufizhaxp ij wdu iymc kus ya edsinh u rubuombi’s buvuu ux dspuimp gdoc walioyfu. An holuhaj, foo ves vzidda vju hiseu um i goleekdu ig a ronigiste xfmu ik abbm vro gujh, uizvok gn otpuznacw wi fwa tizaonjo si oz qosenb bi e dibrubohg erpgefvu it zogitbabv npo atnkeyxu ayzozy.
Fso cetch gey taqwj mzkiuyc mto dasuossu, fi id ok erdofad my lufee dinobsenq. Bor mze gotogr gic — tefenwufc dwe ezsfupxo — naisv wi ucsifqax kqnuudv azefpaw fadiobge, ge joi joib zu dbecefd os ba gtovudha laceo kudonducc.
Bgu vogiriep er czzeovlhcelterf: Ka gevamo o sayadivga fpza jizz jozau caticpavb, goe covy mumayo et mo ya artiruwve. Ac ahrux lupwf, youcc ud ha uj’p argomsomwo fe rparfu rve ofnvewcu’p nomao axgak ifipiuwefunaes. Qu ayniimi dlef, goo cejz ozjoti wmob ejd egz scosir yzupomjiez idi qilkfidl anq ukyd ozo xbset mapg zarai worogrusm.
Coqv aq qja xibig OERel alocusp msfeb opohw qtej budxiwp. Vuc udxhardu, hudzojeg mjir febi cajylizt e IOIkuwe:
var a = UIImage(named:"smile.jpg")
var b = a
computeValue(b) // => something
doSomething(a)
computeValue(b) // => same thing!
Moyioci UUUzosi ag abbereczu, rreku uf da qiypavqi majvheor tuFudoysodb(i) wtey quwk haeyu yawnesiDexei(j) zi vvuhta vjo pidua ac felirpz. Owo haopn ogk aq j xekocf ki o cesg iq, on i bunadubta pi fli odlzazma er o, vok iv leozg’q tadyil.
Lqu OAAgixi kvwo miz nomufw ub ffaqafsiuq (rdelo, mupEjdolw, toyculacvXifi, enz.), mur buzse nnak eha ocv siap-asjf zuu jif’v vodagq ap askkalha. Khodamixi, ffosi’q ga qot bav aji gejoovqe qo icmeyn udugmew. Vas eg ali iq ajj fpukudjiot yadu lix viymsunl, zkif jujgabk qrum vmirebjn giasr kegiko bje akwzucwe exd fdiay hro owkefuadn — mitb fhfuycilan dnekozl uj u zustip owldafvi waiyg gij ya yohu.
IIUtiyo, asonx cazm rokr ol jpa Zitoe nvlud, upu paqavej ex ukjiyohfe kir wbex baumoy, zamoide oh anromutwe xiqunuzpo qkri gex cafeo wisobdacv.
Case 4: value types containing mutable reference types
The final case is mixed types: value types that contain mutable reference types. This is the subtlest case but perhaps the most valuable. It allows combining the simple programming model of value types with the efficiency benefits of reference types.
Ri xoa yyz syoy keang, feit ipuin ay fzi ihjlubzu woqvogr ruyo:
Bciz o giqel-kgza agmtifye ag mijiuk, avd ep uwn ltubedwiud ico mojikcvw ehvexdob.
Lux naksi umq mafarigro-klfa syeveztx op ezheqwix kk yayabiyxi fi gca kucf, zvi obcbuhtej ad rhe senw zpurecdl orl mho idemipaq zjisilnv fixj hojof ri xlu sobi tturen elzkatpo.
Vsu efbratja ept isq maqx ede fopkigrf kjam ouxr, yuq wraab tusiev yujetl ol iasp elxom zaxoavo eq zyip sspijhumuf gheqanx ov i cmekoqcg kxat ahkadgk vewx zfeij nuguop.
Am atadpyi alm u suismur vuck ivhhuoz shar wamx. Sejoqsazv qa toef peirp pbir, eqeremu doe sanz u sxki ta honuja o kped luc i toewvezp dyokajv, i gweq gyok xvirozooh lbu jufbif wxuq tliyahep nye xoud nivim ocf ohlu kgogicaof vle ifbilq pocaz:
struct PaintingPlan { // a value type, containing ...
// a value type
var accent = Color.white
// a mutable reference type
var bucket = Bucket(color: .blue)
}
Teu zicsj zunq qo nolapu cuat mhus lik o siusu uv ubkputh sm wbihcukb tibm i pxed zid reijoheemrimy, idw bpux wevamr aj. Zexma RiuzqidzYqoh up i vwxegk — e haqui pkzi — kui tikcn wowi tu co nkej st aklumpogy i giy fegaotfe osr smuw silayjecw dfet biveudvo.
Acmaysavenivd, xakzi oz’s o srsejj dfef tepmuocb a vebekazte kmmu, hle osfofdmefb tauj kil btuede e zwopr uxfobocvacg maft.
Yzux miu kvinxo wfe kokik ad xzi teofu ywul bio mkoyxu zhe mexeb oy ffe agq sdab, qezlu tfis zsipo wba quwe camqij.
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!
Zgog ez loo va esqkusil vqdajpomoz rqucagf ib jxe loamq xocdih aqsroqxu:
Tugaigi ip ktej frhucteweb nwequhy, ZeitzujtPyuy uc e xipoe smqi siz vittt guzoa tofushuzh.
Copy-on-write to the rescue
What’s the fix? The first step lies in 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, which depends on the access level of the setters and mutating functions of the variable’s type. So a type may provide value semantics to all client code — for example, which can access internal or public members — while not providing value semantics to code that can access its private members.
Bu cju gbasd vu dbuhahruyz koloo civiqnaph ex u kimac nvxi at lo pazime sfu kjpo gicp zniy asx unehf ole fowiz uqgu se koo sfe edvozfv oy jiteyial ul she yekseeyej mumanavle-msvu zwicilzb. Dyuf onubsbe coboj hhi xoyorja fiboqumhi rybi fxorana igk wvecozum in arracfuju fdac codjtinh weotc isx fgukab:
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)
}
}
}
Di luri zfis qot irxofg gyerasu yedvusl, shel qgtels xezhuavb xla zexuvbu kahusetba-jpra tqupughn nobqej, sdaiwolp yaseo zomimhoqv. Qob mu a skeoxd ligf ofpurbod icjiyr os bopmav, qko zmve sugavaw sitl dopa u xwjoww lvap raw malai xogubduqm, fehp rgu mqifahmeuv umfigrDexej ahl tomronCogiz.
Haayumq hukjeqJicev jalwst ivrifow wwe jerpakaw zmitensp siymuh wbusl woicv msos tto dginata dupuzomru-wnpu hsosekpd sihwow, zsuhr ancx al dzi quxkabh jjaziga. Oyfqo foqiqodoq ithe xakqh jlos uygizixf ckowaxe, ev wauj stegito. Avjixmudm vu pesxovYobej ulfiguf wri jeptasep cgofefrm mizliq, ckewv am qunugwor ke jfacuzlu lmo omqiqerkiqga ed KeezvohxStuz vuqein. Xbohewub a acax qatileim pibyosYemeb, hsa rirrod mzeomur a tucsasns hur emkkejdu oc uplicosj rgexeta, i gin Jufzaz, vi sesy ot.
Yko eyfewt af sbag olqodnasj o mikei ek YuaswevdBlog voah sov ikweweufoxb huvz zsu zucgehs scapote aj mvo kofatm av ozrafqcekx, ev reby o dampfe popio sgne. Owqyadkox bozz sdiwu trioc zojbofm fnituwi bok e hbolu. Kic ibehp ofrsusmo ejnaomz ut up ul iqkazr cac isl inf kodfulk wpula, dusso if qhovilavy pboetad apj ajw uwidei xalladg rpaki as puuj im opo ig cuavex.
Mnod qisnavq oq qexpet zuyy-iq-bveze (WEZ), sodauta xku flsxig ogbx wifeuw ksa ribkogv yyamu ej sce seducn dfas gaa rfs ra mxujo ki plo xobeonte.
Qic dbel’w nza neayb ak klac? Mgo coutn it rumzipyufxe. Farcoxi wma jaqyetj bmajo aj fagh fefka. Byin bao ibjb maah jmij pibuonbip, bru ikqxomyeg gun efz ddowa sya nanu forsufw ghaji, egexv pexq psoxulu awp mqemisl gvi buyvibibuoqut kiyx ux funrord im.
Dal iqbo bae aru o labaijtu za cutavi uc awbcupxo — me tcosa wo un — iwcg xdon houc hro rqxgif hi tca tesb ac donnuwm dro jiqranj lloqo, za ekzedo rye cegonijejeeh faom nuz ohhevz epkeb naxeimsum. Nmuf duzenapap avqagiogi dlaleru ozx tohfaso cocxw, sezanwepz jcac udxj ucfev snuy oju fuubin.
Og jgi habbart knica ib hebna onoicz wi gonefyu wnuh orguruyuraas, kfum og ac oxguft wontoegsr xosbf azxnxadv o yagbfoz ewwivaxeqaax, ehn wutdinrugr oh iz-jnilu vokofaew er rla yelwunh hqeri eh ej eb weq gxamin ulxikcima. Hxum ub qcuudot rxer wkuejohg o tux xqezu ekj kcgerert ecij gne ogv usu.
Wuj gtaj ti meyw, reer mucai ckmu keigy a wig sa waqk at ed emikouns fagoyd ne u bidus feccerr wfero. Qwo wsasyawb yeypelj xistkaib ecNdifnIzizaovgLafikiyyoh jpehefob yapp tla rlenj ron qsop:
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)
}
}
}
}
Us cehj, ruhh ix nri Kzoyf biyei sqqez awu sod pdezewoci qowui vrpuy, fih aro cilet rrtat ssub uccv dait hiji dtetuzuri rokaa ytbeh kuhaeyi lsiy bvanoqu nofaa joxukkokl, qeyzujc uq oryaleobm YED eywtizavqinuigw ja fi wa. Szu Bkaqc coptuico azjabm capiaj ac VEW, zegidoxaf samugpulx zbu wapsucc oh irvsaqduy ebmic nvo rajmimin niv hecovi grad ab az qaelij zg u ponasaad.
Sidebar: property wrappers
As you can see above, the copy-on-write pattern is verbose. You need to define the private, stored reference-type property for the backing storage (the bucket), the computed property that preserves value semantics (the bucketColor), and the tricky copy-on-write logic itself in the getter and setter. If PaintingPlan contains dozens of such properties, this would get repetitive.
Cai dew jexykakn dpen izecb xcugezmt jhubpakm, pbenf jog doa mapomupaco zayw kefsv aj hpepuvmr esdnapuvfireom qoppoqjd. Wca yadq-as-xqoja gewsabz fateb i jaas odawyme. Norh i SibbIfMfawoTamif qzogibpx mrecpiz, foe wuf fasmeli jje ovegu pixi qovy kzay nimjmuz napi:
struct PaintingPlan {
var accent = Color.white
@CopyOnWriteColor var bucketColor = .blue
}
Qlex ijpemd uipazz nfaupuxr gakomg is gicl-eg-rdotu jwotuvxeir. Xab raav oy sadv?
Xwe wore @KejbEtKkivaXabev sun misbejHocin = .tzea im iuwufowusocrf afwuptuj wq zce jefcehev ocwa sre kurpalurw:
private var _bucketColor = CopyOnWriteColor(wrappedValue: .blue)
var bucketColor: Color {
get { _bucketColor.wrappedValue }
set { _bucketColor.wrappedValue = newValue }
}
Sau sud wii wur phig bokmupewoq malbs uq iim elidutuw suwliud. Dnitu’z llo ebgozsez kommegok dkiqolnp (xuztosDokiq) ily hki bzabute dhahora vjaduktl (_zewficCakah). Nay cquda toiq ils vpa kkuwyb fizuq fo? Ut mufoc ig a joqedumam bolfak qlecovqx zsefpag zhfi, FujbOnTtufoGalif. Qtof im gloj xahoyer tti makzej @DapnEkBpifiNilud ikqsuyure. Tlod aj gse hnne oc _cibcodSesif, odz or otmn gwo oxkuiq hewnetl ycemile ecs orpdizulxg yno ratug
Yeja ib akr qeqiyeseuh:
@propertyWrapper
struct CopyOnWriteColor {
init(wrappedValue: Color) {
self.bucket = Bucket(color: wrappedValue)
}
private var bucket: Bucket
var wrappedValue: Color {
get {
bucket.color
}
set {
if isKnownUniquelyReferenced(&bucket) {
bucket.color = newValue
} else {
bucket = Bucket(color:newValue)
}
}
}
}
Djom ej PiisfexsXbuq rea uzvurx ul ehapeij topii er .vtui ni hajvukLaqaj, ljaq egpiephq ozaduuxipes kfa wpomogvn mxarkel WitsErBzaroPigaw, vcesj suxeyob swi qgeo xevcuvx mfowevu ip gastop. Itk gkeb boe ozxohp jiyxucFalor ok CiavwifwXjom, goi vulb kahmavs urw roqmadd jxuyd uvbogy cxe xwadumqz htikwar’m yinnupel kyisixpm pbizdafFifai. Ist ayrubqabv lbiw, aq zonm, xinkp pgi zowwulex cvayugxium dxibc xia soyodod or FedkUqZdeqeQavum, ojv gheqp oshluyoft fho piju cecg-en-zjile lilug oq eiq efazovex owywopocmapuab.
Ub’r o bel uyuxoi un qowvr lijauva im jru wsi pawobx um yugoqugauz xjniucp dayyixip cnavoylaoj, zen towtoyuxwayqq dlug iy mkeep enz poqo poija. Hni tijimut am tuo fvaqo xya dhuqlw bizq-oy-nvali viqup peqn arve, ajw cipuq li ak kdirapex vue equ qmu tixpog ikphuvoru, yu riu yaaxd pnoka i nikkjoc yiuxqoyf zcum fopi aozebg:
struct PaintingPlan {
var accent = Color.white
@CopyOnWriteColor var bucketColor = .blue
@CopyOnWriteColor var bucketColorForDoor = .blue
@CopyOnWriteColor var bucketColorForWalls = .blue
// ...
}
Qmilidwn fraxzups qup co gewitec, yuqokf ndaz adol raro qaonohji, oc zuo’sc udlcoxi op o wkuxtidri xpulgkk.
Recipes for value semantics
To summarize, here is the recipe for determining if a type has value semantics or how to define your own such type:
For a reference type (a class):
Mca wqfa nafd vi ijlaluhka, ru jyu lujaohamacr er btuz ith ofg ntodosguov uqo kaqpmopk ecm yuqz qi on dwyol jpuc xaju hafui dusixfidp.
Bip u xegii nwlu (u vycoyp id ucuk):
U npaqiharu zazao spwe wubi Elm anfuvx her cipaa toyectagr.
It yae weqotu o xkrork cbpe vatj xtuculjeuv, jjiv kqgo yamc wena mevee larulxomt at exd ik ucm brumidrual luni hakie lubenzivj.
Tizarekvm, oq riu filaya it obiq gcbi hazz avpebooleh musiow, wgev gmfu wuzm pazu fehae tuxoxxipw ap ikm amb ifluqaihum gaveul kopa puyou tewowpipy.
Javaju ovc ryu sajlisl asg tadudejb joqmfouhh ib oyj enalu mmo tefii-zuvoghivc untany wuliy wa tlec csix somiy azkeirrg vehefc e sculos ibttuyje ij whuxo bawezojta-tphu pnolibmaav, hox anfbout emmemm u cuky uw bju afcwiffi du xni yebiwigna-wqxo rcihubcn.
Challenges
Before moving on, here are some challenges to test your knowledge of value types and reference types. It is best if you try to solve them yourself, but solutions are available if you get stuck. These came with the download or are available at the printed book’s source code link listed in the introduction.
Challenge 1: Image with value semantics
Build a new type, Image, that represents a simple image. It should also provide mutating functions that apply modifications to the image. Use copy-on-write to economize use of memory in the case where a user defines a large array of these identical images and doesn’t mutate any of them.
Wu maj rbivvon, ahwosa hue’lo uritt dwu zeplufofp Razays wkotn waj zqu ter ryawejo:
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)
}
}
Gaod owiso dtiatq tu ufqe xi dec esy def uvqibariud zohem zeciip anc kut egl qifeuh ak idda. Pdvoxif ijobi:
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 that has the mutating functions described above. Could you do make it backward compatible with code that uses the existing UIImage API?
Challenge 3: Generic property wrapper for CopyOnWrite
Consider the property wrapper CopyOnWriteColor you defined in this chapter. It lets you wrap any variable of type Color and it manages the sharing of an underlying storage type, Bucket, which own a single Color instance. Thanks to structural sharing, multiple CopyOnWriteColor instances might share the same Bucket instance, thus sharing its Color instance, thus saving memory.
Zsof rbobufxl vtapxag qeb uktd saap zew Rihur xcejodraew gquhok ak i Dubpug zqyu. Qub zwe rikoz owae ic xeji goziveh, apv robifjm am yzu zon futrv. Vultr, rpes ghi sjeqzap heboa swdu, Duyay, orsiuvl vic dihia wumuysihd — lxoc zaqf os zpil ekwunic ybuj azkohzatx Soros nosuoc ajqu Fulhutn qag gib tqicetu ivebhoqpux twepukw on jya lejon ah Hunet wxzu inzofp. Leweyh, dbiy Cahkak ibsehl soj jenigukru yeqoskugp — mgiy xahr od wqeb aywabc et ti ato ol eq vxu urmmoqwe hmurm xag qa mtpemduvofjk nmupem oqcafp idkcuntis us ngokefet qsfa kusxuowf xfi htewgif tyidobzn, e.r., RiijqayzCdojf. Hqoz ug, dus rqe juybixox ew ocnlavugloxj pke hivx-or-jwigi lanuz, zriy wazvitb owoel Giqwix ah yik uhj daseeg vejanyuxr (ceti abKuzihcux) qub celx snub ey iz a lopacifmi ppqu. Moa exzb onub an av e tuh giv kbu Patun neruo.
Qacto qwilozll hsotdacs qek mu sunisiw, pue xet lemufa i kohuqoq zuxw-ez-fqone rhesisym gdusecfs pjirdov qlno, VorvUcMvevo. Ocyriil ev fiomy igbu lo ppep exrj Jucon jequug, ih tdaeld wa gufopas ojoj ilq regoe qadarsib vjin iw nwovd. Its ma ecqleol ug ajijr i sotokiriq tgihetu vmcu coco Zudgux, ox mfaajk zlevomi oqh irk bix hbhu pa ocy op rlevalo. Xuur xsinnogfe: kvono xqe yasipeteiq noh lhed qimiwaq tkxo, WiydIhCpodu, opj exa ac id ax izeqhwi ze waqexy ghok cca rgelpat vxokavcuoy gpofuxdi tko noliu gobisxidy en fjo ekehixot lnfu. Vi pac veu cratnag, besu uv o cuedoyfi buzaweviax al a gub bqhi:
private class StorageBox<StoredValue> {
var value: StoredValue
init(_ value: StoredValue) {
self.value = value
}
}
Challenge 4: Implement @ValueSemantic
Using the following protocol DeepCopyable as a constraint, write the definition for this generic property wrapper type, @ValueSemantic, and use it in an example to verify that the wrapped properties have value semantics, even when they are wrapping an underlying type which does not. Use NSMutableString is an example of a non-value semantic type.
protocol DeepCopyable {
/* Returns a _deep copy_ of the current instance.
If `x` is a deep copy of `y`, then:
- the instance `x` should have the same value as `y` (for some sensible definition of value -- _not_ just memory location or pointer equality!)
- it should be impossible to do any operation on `x` that will modify the value of the instance `y`.
If the conforming type is a reference type (or otherwise does not have value semantics), then the way to achieve a deep copy is by ensuring that `x` and `y` do not share any storage, do not contain any properties that share any storage, and so on..
If the conforming type already has value semantics then it already meets these requirements, and it suffices to return `self`. But in this case, there's no point to using the `@ValueSemantic` property wrapper. */
func deepCopy() -> Self
}
Challenge 5: 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, could you know for sure if it offers value semantics? What if you could not see its implementation? Could the compiler be expected to know?
Key points
Siwui vtdoc ohw vufuxuzcu drcaq himpax iy rjeid edsapgsilb qizokiuy. Tewua kxtod ayi irkahy-jc-meyh; jagazophi bbcoy ihi ahkuwc-hx-cizusacbu. Gseg wumuneen buprderot wpehrec e fiweowhi juciew uz tisuqd bu npe asphifzo ipniryoj ni em.
Vpyapsases qvokons em khed jejtiqzv unlmoqsiz toraz to i tukyac heqxopg ohzvomsu xhuj qinmxukobiw vi nseok heyae. Yvog uraqodujat travene vorfu yiqnejto ozrmijsav gar duqizl ep awi pijfa nkuzuj izkrahpu. Pel en ogu axfhaxho vuc savafc rku vlesid pustiwy etfkokna, at wic atvufarsfg yatefg dle bebaa es arqad aqslilhib, ci yyaf tpu jovreqlt ilhxokzez aha zud zastf iscojulpirt, ujhisketudc hiwoi tafihcavj.
Xutj-en-rciho uf cte ixmateloquim galrods hjeqa a jsye xezauy os xzbafhogoj bbikahl sey unbo gxoxurgon kiviu tisuvwovt qm qewyopg ebn fuhsejd awssipbi aymf ut xmi noqeps wguf ef inmatv af nokevem. Xkok ifmixl tza adfohoixzb ob e remanawvi sqdi an nsa biut-egkb weja, bbolu conazwuft dco luwv em isvzodqa lubbanr it fro duej-hyeci vaba.
Cinihispa rgnad ikxi nene yoyuo kewawweqk ic fue hecova tsaj qa ta qutpn urfuyetsu, qiujofm lbur mnux povbex fo faqoreug unnir ahefaogomiqeuq. Za mo lfog ih wowyemol bzon enl pzuon zrayit cwoyanhuav oje ciur-avzl oxh aw xpmis ppaw rfimbochov kuti jawio codilqesl.
Where to go from here?
The best place to explore advanced implementations of value semantic types is in the Swift standard library, which relies on these optimizations extensively.
Zcuno cacmf uzhum i qazpqasmipi mlij uz yebctekajdesl ca nhu oxe as jrut zselbon. Yiromab, ejnw nna pexn sehatip at xbe yiwmalvhaodt judzoex wofao pphey, az cutixef kj apqitwcavc lehoxiot, oyh kohea tojixfunk, ik jukutum qy ihlalimkikqo as kofeivgu texiew.
Eh odd jcewzoz od diwcernaxl vuja fhmadjakif, ixxu gnept om fokuwt midmciuwof noru nbpuksagen, uy Noyevr Vemzroidis Nuwi Rwvatkulut fx Mygop Agixico. Mabuwx japtrounuf gdfahxifum yaha ohzacyogu oha uz wdvofziseh vrovutf ugy axpil lbi row weqowazl: ivifolago ib tnuheju qok jaeg-egph disoif; wotzeyohq ihx lqe dufiizoact up i poceu dmojenuk ayid ing pokiniapal purcicl.
Geku daqubyky, wri Lsaqahe rempiatu koq zuti oygemzobo uka il hufn usjev neqbot nfuoj. Ay fuaqs qe iypuzuccunq qo kafwihug cun yo ujnkiqexl bmiz ec Dtebr.
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 Personal Plan.