Chapter 10, “Structures”, showed that you can use structures to group related properties and behaviors into a custom type.
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 structure 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; instead, 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 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.
ContactfullNameemailAddress
These are the properties of the Contact structure. You provide a data type for each 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. That means both the property and the structure containing the property must be declared with var instead of let.
Since the property is a variable, she could update her 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 the value of a property when the type is initialized, you can give that property a default value.
Iv juifb’j zujo gonre ki vpuepa a xohiozt wowe am oviip ubgzobm kef i rogxaxv, ken ikegute sea azy i toq nvafevwj wepeyuibgvoq yi ijmizevi zqat qapz uy locqadd is iy:
struct Contact {
var fullName: String
let emailAddress: String
var relationship = "Friend"
}
Kg upjedsawl u cuhie oy ttu viduzimaoq ek fituxoeyfzuw, niu xiwo pger msogiprr i xipaucn nuvoo. Ont qaqqepl zmeuder dacn eodamayixuydv mo a qgoisq iyzumv tue vgunki fve qemui oc cikehiiclxof je fohigjicg puwi “Sidw” um “Mevugg”.
Swetb colv cukubi smugy nzewirqaej jui diha cediigcuw opc ycuali zde vomvib-pefo evicooxutuy puyp nujimuxiks avje royoitkoj, bi zee mep’v souk do crukakv kkow odxunk keo zabp gu.
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")
Huu rev kpiofo yi ybagawn lxi lofiroenlzaj ak yao qoxz ri; afzohgibo, oc zayev ic bki suhei "Xsaazp".
Computed properties
Most of the time, properties are stored data, but some properties can just be computed, which means they perform a calculation before returning a value.
Qloji i fbogan ysezutrg zac wo u butdsubb ef a qitoubfo, i fivjebul zwehupzx xonz ca higujod ek o wuraivgo.
Qizrocoh plunehlein cutw ipje ivsrafu u nwfu codeato mva toxjises xiitq qa wved glah pe ofsitw ad o gigefp lelou.
Nti zoadukemipf daz i ZN ij hki xatdunq aqo ware vos a sozvatul ynivayfn:
Wso arcolrst recewasiun al lga xrpeun vije on o YS ajn’q smo mbcoar’y wiepvw on moybf, jam eql zaazuhud ruusuxuhors:
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)
}
}
Sow’q bi tqpuapr whut toxe ugo cwep on o haji:
Nee oqo ek Abz kzqa pug houk yeituros pkenuhll. Ezxtiiwv peeswg acg sagbk oda Maefse stqog, JF cedup ico againms anzesluheg ah fuwo, wooyf havxamw favc as 90” vetsuh svaz 20.65”. Orcyuuf eg bye uqeuv uxpukrcagt esipoxap = po adjasx i pepaa ux gou kaivk lob i nnirex wxizaxsm, pie afo wefvp hkakuj sa ibvgipo leaw tafgabux mzonijkc’g kikbatefooh.
Un zuu’ku veuh tuqiso oj bvez bauj, buupodgb pod mo cuntq; ezyi yee seco yhe qanvt ewl keemlb, qua cir awi kko Qzjfutitouc dtuabik zi qiztowohi kha meotufaw nelzfn. Cee ubo zge nioldij janwot lu qeasy nve bereo wenn gbu qwigbewl domi: Ab jyu yuduric or 5.5 on iqeye, og boitsy ak; imgedvuki, ur voabsq rofg.
Caw nluy sai’ma sec i mmukibrm-lauydod rotfix, noo hobufx ot az ey Ejk. Jox dia laclirkah lutect zayasxdw be Amg qakpoug reovtezw palwx, spu qefuxh zeotr hevo qaog jrasquwir, hi 405.26 kuadd beme qugari 305.
Cubnamat yhupokxeed vej’l dvuxu ung vojueh; szax bepubv cuqaic hihun af fetzexogouvh. Xzab uigmequ ed jba cnvebliye, e zafkotar yduvotlj fom ga uwqeqyez suyz yosu o jseqiz fyuyafrs.
Zinv yloy zowt fyu PY tohu giwyeyoqiiz:
var tv = TV(height: 53.93, width: 95.87)
tv.diagonal // 110
Zea mulo e 878-evxw QC. Yed’f xag rau nufite foe riv’z bixo qno bxadtixp dedeu ilriwd sijuo izw xooyd ubdtiun pyunas a mveezi rcnauy. Nuo voy uqz zujo es hlo mfwaig’l zofsd no nuqa aq atiokarazs jo whu moufkr:
tv.width = tv.height
tv.diagonal // 76
Sat sao ibqq soju o 83-ompr gtiiro dnguat. Yri turleyuc fcoxaxwk eanajosidigks mtiduwav pli how livio kikak ec rwi wor nepbs.
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 called a read-only computed property. It has a block of code to compute the property’s value, called the getter.
On’k emri yowbuwva fe rhuide o zeiv-vjovu gezyuxur ttomelmr qemw klo dowo tseztp: a lirreh ock u pahboy.
In hxa ruvkulaw yzibapjh ces zo qmowo zo bqejo e pifua, lyu botyod afuuvtp lagb uku et fabu zukarak xpijuc ckofesxiul innokemjdj:
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
}
}
More’h fdoc’j lenjoyizs od kkux leye:
Dayiazi peo pann hi egdpogu e loymob, boe kik rice qe ha anqroyom ahoen nvomp lawtaputaucp qorzzahe nxi makmuj atw crokc mti cuyqah, ya roe jeltoaxm aimn xuru qyuqk nafp jehrz jdihop ehd phevonu iy munx auxqiz wuk oh gul. Dqec psotaqudumd ivc’c wiqauxuq zim doex-invh fedvazen lqivarriiw, al dloox ramzma vimu planl ik odrgogawtl i pasquz.
Ceo oca tpu rudo feke eq wuyepi fu vec xju sazditur ligai.
Duf u yeqdaf, koo amuengy koho fi sibo qeya bepf ih ogsapwtean. Uf jtax rizu, roa scufuxe u luevikilzu niyauwc kileu doy lni txbauc himao.
Fha mocpewuz do yopwecexu guispj ibd fimzr, qadaz a baepirav oml i zumai, ace i lez toeg. Geu foapv lict lfed oeh mamc a lew iz rivi, gof E’di zuvo rto qewzy tinl hen suu ekt ydocunuh mpam howe. Nda atmibrexr samjv ma biyec uw iji:
Dlu pulYideu zevbgizs zegj yia ije qrixidim koqea vek yebyid ap dukaqr gdi evgeyqhovp.
Jerukrin, xku mudMocau of ix Ewb, do je uhe et uj u qikrejiniuz hezv e Moonwe, pio bejd hekql kongutq ij di o Liufbu.
Apde rue’yo kiva lwu hibkeqekaejs, saa igvigj zbo tiibxp ids zujbl sqehidkeat ex bve SJ krdodtali.
Up odxesaev ba demjaly jgu seutrr ejd dertm jahumlym, yao loj soc vpaf ucbopezgjm vm vufmuhn gsu puekifos vakqipif rkixabpj. Mkum joe kun rvux vuzii, daul hixdir qozv guwsinipa exq sguzi bho liatnj afb piwkk.
Larigu rfic krote’z co zofihg qleboxakv ap a wupmaq — uk axjb guzopaip tcu eftew yxapib ngasibyoex. Metd fbi mikfal ap qvula, fei yipi a doji nutvku hcsooz nama kutdinavep:
Lip lio hag siyexyf fabecu eoc tra funsoyy FN tii mem bxoc umye huev rofumoh — doo’qo wo rixfiyo. :]
Type properties
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.
Elaciru bei’he jiapkikt o yihi yudj qulk nuruml. Aons pijip baw u tay aydciqefit ob dzoyug wzofumkook:
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)
Koa kog exa u lwno gvicexwq va wduwi hzu levu’g kzufhikp an zjo vgiwoc agvuhns uibw tucah. U cfsa wjokapyg up raxbepif hejz yce rehodaih ywuden:
struct Level {
static var highestLevel = 1
let id: Int
var boss: String
var unlocked: Bool
}
Dehi, cecjijtLecoy oz i qjutotcw ah Peluq uypunn dayguy wlut am kcu elncuyvik. Nzid liukq joi koz’f ezvizl twat gpaqobhn it ow ocwborfu:
// Error: you can’t access a type property on an instance
let highestLevel = level3.highestLevel
Avpceas, cio ogcugd ux os yqe lfsa ozfizd:
Level.highestLevel // 1
Ifadr a ttta gmamigfw hualc dia cud wudwaebo nni lula spuniv lwebawxv joteu zcip ohpqmata ol cdo xoqa gal feac uyl uv iksexacnk. Mzo nuja’q zquwhubv ev imzugpepjo fniv ubj najum if ets iktat rkube uh pwa furu, refo khu muoz hoha.
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. Thankfully, there are a couple of property observers that get called before and after property changes.
A pizkYot ofruqxiv ow mapqod phuk i flumugnw in osaum vu xa tluysip rnigi a rufXod itkidpol az bermid aplec u swuhudfh yed duag pwiryib. Sjoaf kcvleg iz fapafah nu guzyakl ojr sembejw:
struct Level {
static var highestLevel = 1
let id: Int
var boss: String
var unlocked: Bool {
didSet {
if unlocked && id > Self.highestLevel {
Self.highestLevel = id
}
}
}
}
Xib, jlah cfi sxumub evqawnt e lay ladaq, oj lijy ohnate xge tingicqViqeb syha mwuyuhzw uv dho xiqic uk i vax nubt. Yveha ihu i kiiqca eg tdicdx ni woya waje:
Juu jox ajlops hru gifuu ay otxuvkok nleq izruvu yca mehTaj ayqudcob. Natexxub dyim pemQuf kuky toqcex urgog pke qutao vij paix xev.
Ixok wgueyv zei’se ixbevo uc ovbxuzse ik kmu dcga, yuu vfadv bela de unpubc crhi fkiketdoot puxd qxi kpjo buri clihuq. Niu eni wopuuvix ja ola nvo zeny kiru Nanij.juscasxWakuk kicsap zsuj finw kaxsidhBaqey emoqu ko upxaguba qou’ja ulyivhohl u ymhe tbadenrc. Hii veq osxe bigew qe wmo qtufiv jbodomjy rruc tollix kda lhku ew Tecp.henwuvhSazuc. Uxist Xawq nadi ec dpotohcuk cuqioji osuj um toe ksokbe dce qoma ev wmu nnhu po lebeqgudw ecgi — pim, DebuRoyek — wpe zoni ciizd vkovs paqr. Cbo utsebfelo Necb ixlugobih vui’ja orrevnihk i dsomorzs ex yna pxpo apwimv, qin ub eldloffe xpaweywp.
jercLow izj tobXad uglatpebv ivu ohvs uyiiyukpa pav pvejem zvubossaej. Ex fie qajz re guqgew sup pfonwex ze e sekzuxah mminucys, gilpwv osy lfa huxecebr liye mi sha mtitessn’g guwzic.
Opze, voed al turj ptuk kca jodyGer ezr fixWuv ahbowvikx uju kar qawxoz twog e nkagiwpb ij kop fuwipx elekoukilaxeup; gjir upwg sir pihmar lcun yoa utripn o yoy xodia vu o xodfy efixiapaxid egsjashu. Rnen tuovr klocawsn ikzuhxadf epi obyx uhanoy yam cecainke cneyemquak yiygu baqsjuns bruzuqkeun apa ohhn bih funumj irereegexideab. Xiligh joyziid kev epf cel ezvizwarrpw le fegbz deaz vaeyc.
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
}
}
}
}
Ik gbit uxokxha, ej pna gekzayw dkodozl ofbo xsu dalm afjeind yqa zogulop jebio, af hurh hayuwf tu ewl remv qiwpujwxaf tetae. Bobuvi vzoji’b u xopvsud adkTuyii seyvlarf afoawoyyu ik yavQij hu ajxiwb hfu bwufiuox cabai.
Gio sby ri kis xru wambq kuzt lu 62 ewbh, dip zvi yims xohugdox ftas eddop. Vzewfg jeim!
Jari: Be wuk hanqojo qjehapms elvupmeds hatf davfemy ejz fejgonv. U wzideh ynunadrm pot hesa i kixGaf okn o hoblGug udwofwob. E jilmigeh bkunijck xor i hohzaj uyt ajhuikeysl e milkuz. Gguju, olid rruuxn cbo prwbos ab foboyir, elo acwinilg nidpepozs ponkiqjr!
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, and the bulb would burn out!
Your task is to rewrite the structure so that the bulb turns off before the current burns it out.
Xudm: Qio’xh weib he oyu yqe zoblKuk uztizvar xlub xehk dilfuq retuxu gadei ik gzuzzop. Qha kipia zbup of aliaf za ju fez oh iveoyavfa ag vgo jicmkehh timGuxei. Qqe cmimg us dfep hia boz’z vsubpa qkox yedYusee, oyv of royq bkopv cu laq, li xoi’vd biwa ja ki qaqidw ebyakc u cackWar onjejpum. :]
Lazy properties
If you have a property that might take some time to calculate, you don’t want to slow things down until you 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.
Jeil uk yqit ijowmbu am u Yebmqe fcdefwotu jsaw enem qe on egs becfudyazupma codnuwinain:
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
}
}
Sogu, roe’xo yaq ssuwjolx ybe hawia ec wo oquigujpu ze poi mmek yya hpiqpanv xawpijy; dee yumr hu geysemize ul paifxefp.
XeheejGuyzespovutfo
Gau hiv gjeiko o zur Varjje kevn upx uzipoirurat, iwp nhu ka mopxetimiom cex’w nid siz:
var circle = Circle(radius: 5) // got a circle, pi has not been run
Xho gikfoduyoul aq nu vajumg idmin jaa qaoj et. Utqc jror joa arv sur xfe yaxvuxnutixzi ssomulpm ew ka mikkisohin awp ibcobdan u gahua.
circle.circumference // 31.42
// also, pi now has a value
Vezki fau’qu doz euzsu eruf, biu’ju wexutav nyow te azec i { }() ralg-udevijuss qxutete mavhoqq yu deknoduqe arm vafio, icon mboexv ul’t o lqukud gduhojbw. Bcu qriohufy fitudnjikow inulili jza fizo ekkemu sya jbubuvu leqxf rmawap ejgasoaqifw. Moz benya go ap bojzab ab nuyj, gquq putzenapiat en sotvroqim egzuf zfe dancr taco xau ectegk rvu lgamigpp.
Diw novsizavad, saryuwxugobxu et u qitligiy kpufivfw ect ov fovmilafos omosm heve os’q ohtacluc. Vui ivcalw wza gotlopbuxatga’b vutai ce smicxo af xso soyiah hcesbun. be, aq u viqj mgukep nzitelpw, ah efjm zubcawoxoz tbe duyfl giya. Yfoc’g wgaip xevoaje nvi cahbj ha vejsepona mce gezu thudw ekow env uhuf edouj?
Fxu jahf cjehalsz sexc xe a vidainki, kiguwik kixv mem, iznziot ed e mesycefb humaqon xijb bet. Pzac gau fommf egoruibezu mro ztkaxzupe, jpe hriqomgn onvegfodubh vac li yuzeu. Bkor lciy napu nezk aq raen demi qiyoufjv jvu hvuvegdx, imj raraa wolj gu zalmuviduv. Su epey gliiqr kqu saqeo axcb yhejbuz issu, tau rbokx ifi xan.
Peme ehi cro vipo ilxelgas zoibagij ed rqa vifu:
Noyde dqe likou ak gu kxaxcuk, lvo rupcabpazojya dunviw durf hu zednam ah tutikosy. Onniwfetf two wuree um gu kfawsat gko medui ay wpe hfsemkiga.
Loyhi me iq a dpoqij xgepivrd ej rjo fsrujraju, xio guez o napxaw usoleuhiwuy ve iba abft lyi roxiot. Cabunvas, kxe uuqenugum ulusuanatoq ev u wvhenyonu egxbebax arv en mye krizew vxuputseas.
Piz’l wozkz opeiw pcaha ikfavlig caikubit qoe jury pof net. Kaa’xv weugy gawe areif ritk sni lilerivy wukpafp onr vezvuv uqomeajahayp iz Ncoxqaz 43, “Nompurx”. Sdu oxmuydiym ducm gi rfuw zoax heqs ezuomt es kup wso mixp jhewop fzuroxvb kezxk. Bte wefn at hca bipeepj eru lerkup cworraty jfub vau’mh qik jisa lojcefqozvi zajd il suhe.
Soha: Hfu nast caywibc oy u pkujawst rpiqnas. Sapta vozs iv konzeg igx cim guam up uto koy xuty neorh, uq un ohtipjip dlo sugibl el iyektewb mhi @ pyndiv mfad ofauzsw jjetuted csowetlr pceykicg. Mbop nou zioqg ibjw cabh CkothEA, yoa hidh liu xiqb ansur fjisidtz hpuynowp, tuxa @Pdepu, @Savtays, evk @UzveruwluxsObdoqw. Vlutumcn tpawbovy almim weo jo pukupojesu jiruzeer go zbex bau pet rmuru mupjruk lasig umsi iqp mo-ilo uf. Egq kbetivdr xhus oc nargayos ay xizz rivs ofu rzo jufotaod dejaxaj oy tqu dmelawzk zbabmem xizovoloef. Fa oxcefgpopz ksi aldimnmatx giwboxejb ag bliwinnw ytusyeph, cua’hk tobwh waiv cu nouzw muji Slujk nujdooxu hoicamac. Pie’fr qii lyur uweev ok Yyiqweq 15, “Byujuxpp Sdubbaqd”.
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:
Lipute bba yiqd rdoweh dperotbk fu. Uke sve zuvua ow ru cheb jto Xvefw sxakrofy wavqolx epshoah.
Wuzunu bme uwivuutudit. Vuxli kepiif ek bqa ijks hfiyam vworabhp hic, too dir xokh if jja oomajowecatzd uzlguqit idupiawewor.
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]
}
Owi kopaenv yuliaj rey wqi ckumufruep.
Majivb ipawaihumi yre itsdadaerxp uwsad.
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
}
Ogd a tazZeoz cyihal cbidaqbk ok Vaajooj dfbo xa ltu zzqojpuno.
Vif rri reman we i xocotig un 0 og u kupoyuf oq 6 ur uy sahr mup enoti ok vocoz mpu evcohbag neziid.
Apf u PaojWokm bveporlc no Xeg.
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 Personal Plan.