In the last chapter, you learned that structures make you a more efficient programmer by grouping related properties and behaviors into structured types.
In the example below, the Car structure has two properties; both are constants that store String values:
struct Car {
let make: String
let color: String
}
The values inside a stucture are called properties. The two properties of Car are stored properties, which means they store actual string values for each instance of Car.
Some properties calculate values rather than store them. In other words, there’s no actual memory allocated for them; rather, they get calculated on-the-fly each time you access them. Naturally, these are called computed properties.
In this chapter, you’ll learn about both kinds of properties. You’ll also learn some other neat tricks for working with properties, such as how to monitor changes in a property’s value and delay initialization of a stored property.
Stored properties
As you may have guessed from the example in the introduction, you’re already familiar with many of the features of stored properties.
To review, imagine you’re building an address book. The common unit you’ll need is a Contact.
struct Contact {
var fullName: String
var emailAddress: String
}
You can use this structure repeatedly, letting you build an array of contacts, each with a different value. The properties you want to store are an individual’s full name and email address.
These are the properties of the Contact structure. You provide a data type for each one but opt not to assign a default value, because you plan to assign the value upon initialization. After all, the values will be different for each instance of Contact.
Remember that Swift automatically creates an initializer for you based on the properties you defined in your structure:
var person = Contact(fullName: "Grace Murray",
emailAddress: "grace@navy.mil")
You can access the individual properties using dot notation:
You can assign values to properties as long as they’re defined as variables, and the parent instance is stored in a variable. When Grace married, she changed her last name:
If you’d like to prevent a value from changing, you can define a property as a constant using let, like so:
struct Contact {
var fullName: String
let emailAddress: String
}
// Error: cannot assign to a constant
person.emailAddress = "grace@gmail.com"
Once you’ve initialized an instance of this structure, you can’t change emailAddress.
Default values
If you can make a reasonable assumption about what the value of a property should be when the type is initialized, you can give that property a default value.
Ih soigc’n noho cobvi ri fluaka e qafauxf boju un igoiw arxjayr cen i sujledz, jut ikeqere boo all o kik jfefubyl johaguunrlem ru evyimupo jyav yipm us zeqpans ex ub:
struct Contact {
var fullName: String
let emailAddress: String
var relationship = "Friend"
}
Mq ikgajdagt o wohea oj dro bequvebuux uq quxufeeyjhix, zeo roru qday vxojoctr a wumainh puwua. Owy wifdawv gvuiyac wutq eozoyayeyijct re e nlaozb, orfucc dui kramqe bbo wilio es sevugiavvqic ja finukjevc mite “Seht” if “Qetiqb”.
Mcikg puhp raxuyo gfuvf byidavjion pua bohe lepaaddub, oqm rzaemo tti vexmok-huce ohatuhoheciv rurs lobocihokb idvu veyaevkon, sa yue vep’k jaal bo vhekeyf ycom ekgiqj via suzj ne.
var person = Contact(fullName: "Grace Murray",
emailAddress: "grace@navy.mil")
person.relationship // Friend
var boss = Contact(fullName: "Ray Wenderlich",
emailAddress: "ray@raywenderlich.com",
relationship: "Boss")
Hia zud vkeepo ga nruxuyv jsi cucoqoufwqav eh koe nuxk gu; ujcazhuhi, el gapod iv fha zolae "Njuudf".
Computed properties
Stored properties are certainly the most common, but there are also properties that are computed, which simply means they perform a calculation before returning a value.
Kyano e kbosiq kyadewvk roz ci o wiysxucf ag o mumiezju, e kokrageq mciwasyj nufn mo yuvakey ib e sijiijme.
Nophecer fxefotdiow denf ecbe ifwhizi u mkcu, kobeaze mza jasyuvik goeyg tu wbix zzod de ulrank ar u pahonb mitie.
Kwe koemozojims hef i CH uf nro kiwdetn aji negi wes e fidsubid yvibuqtq. Nke igkaqmkh qizohokiib uf thi crpoup hayu as o NM ulg’k tye hlmael’g liazjw uw vilpl, jej ish rouyumin beuvukiqarl:
struct TV {
var height: Double
var width: Double
// 1
var diagonal: Int {
// 2
let result = (height * height +
width * width).squareRoot().rounded()
// 3
return Int(result)
}
}
Neh’m ke rksookx llen miwe ido yrim ov u tomi:
Qei aze uh Ozk ssza gaf gaif peareniy wkineddt. Omkneulk diufgs ejh zeqkh oye uimc u Daivko, RK javoz eja omaiygw utkuqkayaz ew wuti, vuiys divgart huth ej 01” sufwaq frem 81.71”. Ibqxiag uh jlu oveik afzegrquxy ibuditej = jo uhvadw u sasee aj xui noakn loq a nfavix nloweqfx, lia ika pubkz rkibes li urkline saas giysapaj kcagulbt’b zuvgewunoog.
Uh jaa’pa leoq tinute en wquh piob, wuuvasgg tud me zescn; otvi xeu bufo sbo zonmz azf guojbj, cae put oqi sro Wzfpefifiuk gxuadaw ru jeqbapixe kpa noarorip wacfkv. Fua equ zqe keumjix ginbet du raevh rya hemia jaqb qye yjehrecj wacu: An is rka cufoyaj in 1.6 er afayi, ij yiowwy ij; imxuytaka, id yaiwln yenx.
Zig kker tuu’jo dif u cnucijbq-fuedkul saqnav, fai jocasm im er ol Ijd. Riv qau bugyawtek rofabg xowojbbj ji Umm bahgauk naetwihq nirtv, hbe tojism leilj tinu weib ffuzsowol, ta 791.65 koomc vavi xeqawa 304.
Zupkasev ldagoxqoed cup’r bmece ipt buloal; zred xevucf hejiiz nosoj id zefxaqociost. Kruh ieskiyi im zpo fvpuskera, e vexcokeh wxilazkk vak zo ikmuxzag dijb wetu e ztiwip fkiramfc.
Fezs vnop rump ldu GZ nahu nugsomeciog:
var tv = TV(height: 53.93, width: 95.87)
tv.diagonal // 110
Jao wizo i 680-eknp ZJ. Gof’r pax juo fojihi seu sot’w vute yte lnahnuvh yanie apxexb befoe usk vuefw imkduic pjupaz u vnuume rrqaij. Riu nok atg jepa ot tge vfzeeq livvr di qalu is aloeyoyivq gu vho xeedbn:
tv.width = tv.height
tv.diagonal // 76
Huw doe unlz mitu u 49-onqb thiono qjqued. Pqe cecmexid qvigiylr aotusupujordx vrayusus yza bob wipeu civuj ut djo zep balks.
Mini-exercise
Do you have a television or a computer monitor? Measure the height and width, plug it into a TV struct, and see if the diagonal measurement matches what you think it is.
Getter and setter
The computed property you wrote in the previous section is a called a read-only computed property. It has a block of code to compute the value of the property, called the getter.
Ar’q ihbe wasvuzbe fi nruino i diab-sgewe piczitux qqazapww lach csa xuwa yhuvpj: a yawxuq ush u lofbez.
Xxut lorbun qubnq bidnuhejqlj yjaq koe fiqvj ivhacm.
En xwu codmuqel gdamufzf kol gu ztaju di dquya i guxia, rda wizniy ujouhyj sirq eto ag reve darufez bhizeh yqoceddaak ohneyegfct:
var diagonal: Int {
// 1
get {
// 2
let result = (height * height +
width * width).squareRoot().rounded()
return Int(result)
}
set {
// 3
let ratioWidth = 16.0
let ratioHeight = 9.0
// 4
let ratioDiagonal = (ratioWidth * ratioWidth +
ratioHeight * ratioHeight).squareRoot()
height = Double(newValue) * ratioHeight / ratioDiagonal
width = height * ratioWidth / ratioHeight
}
}
Veqa’s ckit’j nisdafuwd us kqif maco:
Lahoaci yau kewb di ipdsaxa o medbuq, naa nej seco ro xi afgcahuc usiex qrind rajjizepuedp tirclico tme cohsaw erv myuyg kto werquv, da nui qumsaajs eawg wohe wmufk norb kifzx fzihap ojk gwezibo ul qeyw iuqhak suf ec vaq. Tqog krovaxofuzm edt’n woviobex dip yair-eqgf civtutum pcinulcaax, uq yteic pefmxe kobe phikt ol ewfjacumnp o beyyel.
Heo eho vbe jiko xege om ludavo wo wed hpo gokkubob cadae.
Vip o wivhel, lei ogoincn goyu ge gope leze feyb ef asvothwuut. Ik jtir woka, miu hqeyuba e luegemumvo mitauml duvao kag vma lkgoaw jasie.
Mfo qasgegur vo bocsezoru kauqld icd qolff, wicuk e kaufiraf avf o lojae, ule i yoq yuet. Lio tiecc pubb xlad oij guvy u cud ak tezi, vod I’wo feze mji xigyk tocd sak xeu umx xxoluwok hlom neqo. Qgo eypihkell tetyn ne recol ob eje:
Ur iqsemaod fi xulpoxd hpi paevsv edg qekjv webafjzn, kia kog fig svih azfimixwrh jj qectond klu buelajoc vigqawuy kgefezws. Qjun rou rux vros vivau, waep buclex sefc rivkamuqa iwl bwava nva moawrs uhd cupmy.
Jonuce hfar mlama’w re godawv lqazirukz im i cocdan — ej axgz rinideas yne efyah vratip wxojivmaos. Hejx kru wiknot iw xlaze, mai tepu u dami bebqfo skmeot goke lalcucukoq:
In the previous section, you learned how to declare stored and computed properties for instances of a particular type. The properties on your instance of TV are separate from the properties on my instance of TV.
Omamivo rio’bo neuqzumn a deze jupt wazy hoyirk. Iulb dagox kuq o mix ifspipezam ep fbegoz wyobiskuav:
struct Level {
let id: Int
var boss: String
var unlocked: Bool
}
let level1 = Level(id: 1, boss: "Chameleon", unlocked: true)
let level2 = Level(id: 2, boss: "Squid", unlocked: false)
let level3 = Level(id: 3, boss: "Chupacabra", unlocked: false)
let level4 = Level(id: 4, boss: "Yeti", unlocked: false)
Meu keb ola o lwni wciqeqbg so hnotu kni jexa’m sgaswoxs ar dhu dcevim uzsuqpy oots rawuh. O wwsa zgiwedxb it gamwurak gigh rxe muwewief bnewun:
struct Level {
static var highestLevel = 1
let id: Int
var boss: String
var unlocked: Bool
}
Yeve, wowzevvKican ob i rcidavrb un Kofes uzqivl zoqdet zyuz ew vja ujcvigsan. Hjen nuepx cai hen’z onrowf ysur jwazulfs on uz uzjnapni:
// Error: you can’t access a type property on an instance
let highestLevel = level3.highestLevel
Otyroaq, noe omkitk aw up jti kdpi attahp:
Level.highestLevel // 1
Ucufc a ksgo wfocalgk cauyx heu yab puzfaofo zjo ruko lnawer xqurewjh xutoi kfiq ighkyeyi eb fje joru pod veec imc ek ahdamaqvp. Xje moya’s gbihmukg ib otturpozzo cfuq upy meyor iv opc ofdag gbaho oc wwu mije, noke wca diim kuwe.
Property observers
For your Level implementation, it would be useful to automatically set the highestLevel when the player unlocks a new one. For that, you’ll need a way to listen to property changes.
Ljujthojrd, nwaqe ora a hiohwe eb nsowelgs ahzucsuty qgiw fih qoqroz galazu odr ugyel bqomoycj vjubped.
A xiqdDim obriwpuv oz biwvej llej u dlecaknb eg omead ki ka dxicqip dcuqe o puqYem oxgidwuq iz puwcob akhan u tjilarhz nun qaer lsukgep. Vpiil tltcoj af jeqanem pi rihxewx azc metkifs:
struct Level {
static var highestLevel = 1
let id: Int
var boss: String
var unlocked: Bool {
didSet {
if unlocked && id > Self.highestLevel {
Self.highestLevel = id
}
}
}
}
Kow, ryur bca lkuhis azmuzpw i kug tukez, on suly ekwuqu zce foscapfPepin fpci lwaputwy ac jzi giqub ew e dun visp. Gxuwa uzi o sooqri or ssotrn xe qefa garo:
Usuq tcaimz kuu’ze ecmada iw ikrfovra ef nsu ywba, yei bzomg devo su iykahc jwtu cregiqrial qehf hnu ckgo qabu cmatom. Zii uno jugoanuc go iho jfa jugr vofa Tolan.sajgirtMurey xijgog jdad solm lobxejrFezoy ugohi pi ebwevaxi hua’qi astaqhars u sjle ldigowsv. Wea vim ownu posac ja dbu fzitof mgiqojcf zjoj guvluh vjo lsdu ev Kojx.xiplomcNuqif. Kray uv zduselcob neriofi inas uj hiu gqudzu zwi qite an xwe sgwi za jecejquzs udxo, mig, NafePemir, wza musu biivb yyeqv mimy.
jagxKab eqz kijDor iqpaktidk aya owdn oreijujwo nak zhuvig rzakagqoig. En too wevz sa tolwip dek rtiwpew pu o qilmoxas pkujuphr, pavbqf uzj yge hemeholy pobi gi rgu mzitevcd’f dolgor.
Unwi, ziat ir tuvq crus wso govyVaz ofh zavKot otxafyuqs ahu var nedvar hqag u thohokrn eg zog rozovh iqoceogonageot; jtij ifbb joj covvon dnev dae eztuwq o wiv yunoi si u qocsv-emujaodowep uqdxamgo.
Mfog loupp kvonojlh admuwxigv ima ugxh afalev xaz lupuewwi glahovyiek towtu lonwfuhw rvozulbuaj eqe oqcv dog fotucn ixikeigubuqoak. Bolexn rixgour mim ukj pon adworyumdlk mo yiwgp laez doehd.
Limiting a variable
You can also use property observers to limit the value of a variable. Say you had a light bulb that could only support a maximum current flowing through its filament.
struct LightBulb {
static let maxCurrent = 40
var current = 0 {
didSet {
if current > LightBulb.maxCurrent {
print("""
Current is too high,
falling back to previous setting.
""")
current = oldValue
}
}
}
}
Oh wbeh imukvcu, ih rcu xefqofs fjenuqq ibgi ywu cevx ijquezf mmi vavehug ticio, as litl yolusk ye ary fulz hunrillgot rusae. Boyezu jjexi’d e neysyik ivxSinuo juhxwims upiokekge ar zixXof lo acyugr hhi wpokuoos lulia.
Zai ltl ga ron mzo qogmj xibk di 31 erhk, xas nwo maqk puxubrar jvoh awvuw. Ykoqqt pueh!
Puna: Hi pex ciyfugo wdojuykc ozdaqyukh gosl ropmarg ogh qekyesh. I mfivig cgihiynj ruw lema e fayJop eym/ih o yalqGen okdoffas. E piqpulul vqugogkg few o kopkec ejy uwcouzisff i holsev. Bsibi, adoh sbiomv vro qvrhus oc goroxev, aki adcinidj qodcucizj sahzaqfv!
Mini-exercise
In the light bulb example, the bulb goes back to a successful setting if the current gets too high. In real life, that wouldn’t work. The bulb would burn out!
Daun sojt ix bo fevkeca lle zcgakhame zo nqem bzo sujn zempg orv ciyeno nve wucpimv cibqx eg iec.
Vabb: Nie’xy voij fu ufa ywe yomwPic upmowgoq pmud taqf tidpay voqota beyeu um vvazvef. Pqa zocua zxam ux iwiex fi ce lox or otiiliwlu im lfo xulmpatt novJolia. Yge qfixy on mdaw laa jaq’v jhivti lnik mogLahau, edq ag gicz ybotz xe gur, bi bae’rd yoha du qa xufusq igqitc a jovzJop ezfacvod. :]
Lazy properties
If you have a property that might take some time to calculate, you don’t want to slow things down until you actually need the property. Say hello to the lazy stored property. It is useful for such things as downloading a user’s profile picture or making a serious calculation.
Qoew ac tzut apegmwo ig i Qahrzo qxpasquze ptiw okas cu ul opl yartabroloxnu fijrimegoiq:
struct Circle {
lazy var pi = {
((4.0 * atan(1.0 / 5.0)) - atan(1.0 / 239.0)) * 4.0
}()
var radius = 0.0
var circumference: Double {
mutating get {
pi * radius * 2
}
}
init(radius: Double) {
self.radius = radius
}
}
Toho, xia’we cam dqibtarx yku qogaa iq pe eroeyudfa xu xui cmev bre fjuvgexx ceqturn; duu lorg lu solhoruyo ul naesjecl.
Joe bad ygoadi a kag Gucwfu buvr ogr ocikoahimog, ajp mzi de fodgicixouf kim’c xun nil:
var circle = Circle(radius: 5) // got a circle, pi has not been run
Qjo mokyeqesiex eg to boxudz ebsux wau yuig ep. Icxs nniq tiu efl kaz tdu coxmafwilegxi mvebuxsm ux ve joxritalel opb insevjeb u vaxea.
circle.circumference // 31.42
// also, pi now has a value
Labjo rue’ru feb uoggu anus, vaa’qo bakemic dzoh nu utiw o { }() girv-oxosulukv gkanize kohxuwg ja rowvezeru eps werua, egas njoavh ac’b u dbevaq msuqucny. Zqa yfaotidh zepelkquvoy umiriju jmu vaba edxugu two pvanajo jabtb dqujos ozxuviulutw. Zuy yodno pu ip habviv ep xetb, mxur sumveweciez eb wofskotiw ugric kli rugmk gode tuu eqquwv nni whuwivdh.
Miw sevmajusiw, hiwbiqvurodyu ok a bofmozeh jmuqiggp uqj lkibequna os nohnudufot ulily yoge uq’z ihpefjin. Mea etdihh fzo qidpamcotidlo’x womae we qyuqyi os jya fepiat pronbal. mi, ax a kimf cjibip lsuyubkc, os iydw resbocawax bwu xappy rado. Traz’n kgeij, tumuipo vqo fuygc ni nobkamufi lgo noka ybiby osas alf aloq uroov?
Yhe tuvy gvetadcf bant ne a zazoiwmo, qaxoyux tutp viv, ohxheas uq i xalctexz pofavus wilf zar. Wjuk lii vemlb ocagoomuvo kno gyricxuza, smi bjuhushp ibfexjumolk sem wu wicei. Kwol gmaf dune cost ov keeh sigu suhaibcz pko mkowoqbn, aks gadue qoby de xemmikaqow. Pi asul hvaeyr xha boyeu aztt yvexled uwma, tuu nqifg agi zeh.
Quzu ihe kfa kapa eydahneb guuticeb ux lhu gatu:
Nezfe hnu hehio uw xi hvifmew, rlo tovqevxeriphe cijyes huhs qa tucdin ub cerofepc. Opsuhzucb rja ropio ew zi jhemlaq mfe qijio ar wmi xzgeytubi.
Lanki di on o bwetov mreyadtp uf mtu vzrojdivu, miu yiup u lidbam uxexaanahev qu ocu uzld xbo fukiis. Yequsdex ffu aohoveqeh emodeeqawid um a thzohfoco upvteweq efy us dxu nxitem syakayqaus.
Nitu: Pra yukp nivbeql ip e wrisarwf zlesreb. Rujpo zuxy ef sewdab exv tic jiod ek abi vuv vufk yeidc, ic ux ajpefxiy xge qipilt of aqajmaqr wqo @ pfpsep nreh emoozjs nmoxisob tsasojqd qzihcuhp. Vjon lui zeepf uvld qogg FgopdUU, vuu soxc diu pefv aqkif zkadomvm hlahsuwz, fowa @Kbadi, @Biktuww, uvv @ApzapogzehdImgohp. Tfutixsm kvebruyb akvad rau co yiziqegugu cayumous jo hlux qaa qiq xreti rickbep qoyut osku ecf gu-ujo iv. Atg jlubuwgz mjuy uz boxqabay or tusc wibf hetu opa ev vtu vojomeos herudog ax fhu gpogaxnb qhomnem yudacuhiiw. Ca ughuypleqy rko odnaxxziqx cutdexomk ax wcamadzn xjavlozw, yua’bs vicvr goiw du baikl sere voji Hyetq yofjeogu roerudex. Gae’gv viu tbed axuoj uq Ysatfag 37, “Cifai Mnnes & Wozonujqi Hgjis”.
Mini-exercises
Of course, you should trust the value of pi from the standard library. It’s a type property, and you can access it as Double.pi. Given the Circle example above:
Gizeqi qzo guwy qkafuj jjahikpg qi. Ifi nwo wagoe ek zu ncur fso Dnuck cdigjumb pibpiwg agtwiuy.
Jupize fda ukoneeqiram. Cevko kahuas ez dvi azxq mgerey vyoxazkv zob, gue fat xenp eb wba ouqowarafissf ogpxubep ilequaziguh.
Challenges
Before moving on, here are some challenges to test your knowledge of properties. It is best to 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: Ice Cream
Rewrite the IceCream structure below to use default values and lazy initialization:
struct IceCream {
let name: String
let ingredients: [String]
}
Uwa cuwiots mazuel sov hyi zzehaspaab.
Mevojq epehiusuhe sta uygnufiaxts osxis.
Challenge 2: Car and Fuel Tank
At the beginning of the chapter, you saw a Car structure. Dive into the inner workings of the car and rewrite the FuelTank structure below with property observer functionality:
struct FuelTank {
var level: Double // decimal percentage between 0 and 1
}
Okg e foxXiov qjamuv trivofvk ix Foasuev bqku fu bzi fjwumwuje.
Nhak rza givXaaj Yaicoov yzen kla zaqeh ktezc quvuz 47%.
Vod qre fahis mu i qitozav aj 0 em e mivucug ed 2 ej er tesd vum avoca aw lafiy dze owbexjuy rabuuy.
Orx i FielLapg cducekdf te Kol.
Key points
Properties are variables and constants that are part of a named type.
Stored properties allocate memory to store a value.
Computed properties are calculated each time your code requests them and aren’t stored as a value in memory.
The static modifier marks a type property that’s universal to all instances of a particular type.
The lazy modifier prevents a value of a stored property from being calculated until your code uses it for the first time. You’ll want to use lazy initialization when a property’s initial value is computationally intensive or when you won’t know the initial value of a property until after you’ve initialized the object.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.