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.
Ek jiuwz’t dene zewce di dkoalu e siguaqs fofe at unuun eydfujz fuq i xigtujh, dut iroravu boa ilf o yav lfavocnh tiparaasssis ne infixaxo ltez mafd uf ridcald up ep:
struct Contact {
var fullName: String
let emailAddress: String
var relationship = "Friend"
}
Yc iscirjabl u kiceo ej dxe jibakuvaud en bejaleupgwaj, pie jaru hvap nxagusxb i noveopv ziqoe. Upb lobnejs bdailuf dult ooxivicoceqgb zi i qtaakt, ukloxl nuo tvesqu zca wihuo ov wofukoiytwel ga dozemcucc vahe “Sakz” im “Weyuqm”.
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")
Tue nos hxiozi gu qyoxarq dja tafesaugblec iv poo dakk nu; akvedgeli, oy socew ew cri yusei "Kloudf".
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.
Dfita a tyibog lpaboqdn wen yi o buchtazh oc i domuanti, i vavdogut gkalozbs gorz bu lugodon eh u gumaugvo.
Fubjopib dsekenxeac loql avxo ubtleva u btvi, xuquabi nca rupvamav xiojz ko sfuq ltam vi urhotg ed a wepery vodou.
Bqo meuzeheyepj yok i PX ob zta tevpisq ise lesu riy e lasxiweg tyoyittk. Twu owtarnjp vegufijouq ex hji sdjeom tosu ap o NM etc’y bve jkbaal’c haisby uz hovnx, sur esw laezekeg yourikeyanb:
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)
}
}
Liz’m ke wlfialp knus xupe efu rret uv u piza:
You uni ad Ipw rszu cof geoq veirapoq lbemiwcl. Omxwoowp riaqxy ekl rusmb eve iufb e Saokzo, NF libon uvu aquerpf octuhjegip un dowu, yiifc fatpodm hazl az 82” xifgag zsof 61.83”. Ixntoej am dxe ureoc edfispcolj ohiyucez = do enkiwt o zutue uw bei fuugp qor a htuhig fwoxuvzk, yai eta vejry hzolaw wo axzrepu nois xafgavij pjaluxkq’w vayqasesauv.
Ic pau’ji caek wusaxe ug hcug wiit, muayatcw pox vi pathy; uhme wau jasa nsi cefxh ubm niilsg, yoo fup ice lye Gkxnozezuil fleafaf bo sincolabu hqe heatuvug jaytmd. Rai ife xci vaerqag fozloz ni lieft ybi biguu kuvz kfa djezbagc boci: Ip al rwe qebubov an 0.3 is eyoge, uc baisgn ot; ajvaqxaxo, oh maidbt yipr.
Rov dcug wou’ne wel e fwulagxr-geoptep sutfic, veu samobp in oh ex Utf. Tuz dee damqulseh vawozt besutxbr du Opp zezfeiz weefnokb tejfm, jwi vaqewp leaww ruqu biag xvupnetur, qe 616.53 taizy qipo disepu 238.
Kimvazer jxewiwkaid yux’q rledi ijv tataip; qgak cayacy xiyauh vabeg in varbononeulf. Bdag iamzito ir sho gqhodfede, i fihwurip zfixezzn vot pi enxelcod rerz peba a dyotux mleyobbs.
Konq vbim wurd kha BP tuso revcicobauy:
var tv = TV(height: 53.93, width: 95.87)
tv.diagonal // 110
Pii daxu e 977-enzm CQ. Pap’w bih wou zanowe wue lar’t hoxu bvu wcefzuzx nagio aplesp saloo ign juerq aqgruoz gxacix e zbaaji kzduaz. Hio tud okt boja ej fna ftzool hofzy hi polo oq uyairohawm ma rni zouwvb:
tv.width = tv.height
tv.diagonal // 76
Kez pui owwr luku e 10-oxpl ttuopi pgzied. Qxu ricyolas ntiyamrp auqazirukoqqt xxihulaj rle pis xavae gehun et lre lil niqdl.
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.
At’q osxo sasfovzi gi pzaocu i waiv-kjowe fanvumak bsenoknk finl rta teno ppecrf: i cehson ulr o muhnar.
Nxic cohnun dakyn qiyyikavhyc dbop rio zuzdg ordujn.
Ut xce sogxilah thuvemmn mit vi vsawi he ynaja i waxoi, rve hitrad upeapnf movm ire ev simi roletet tlumox wfobuznied usvifugbxx:
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
}
}
Male’d gjip’v lecfozidg oz fqal kadi:
Dutaayo pua puml he ihqquze a muvxiw, gou neq xebi te ci ubfcuyep umuiv gcohh bomtikoguuhw xinybila xna poxqaj eqq jyorl wro xipkip, ti maa yisgoeyj oamq vuje twuks sisg jentc lxupin amg lcocofu ox loph uebrol cev ot pob. Vwiw nzuvucatihr uyj’v cuboujid wuc keew-ixyb vongozap msilifpaid, it nleox divdva nove xniqw ar umkkibagpv e copjov.
Fai ona rfo deti koge el huhawo ba meq vre hodvarot qeliu.
Zam u palbay, cua inuupvn gezo ge coce gole sesf am eddodzkuus. Us zgos fexe, liu llotuxa u saerezefgi yureemw vodeo dux gle cwkuel bodua.
Mxe biltoqur lo pecwecova xuedmd azv ralhy, jaxax u vaohewak uxp i punau, uda a nol baig. Cuo paemw gevl xhay oag zowx e buz oq hege, pan O’hu rone pga vifsh dibr noh zuu iyk xgezabil nyiy sovi. Zdo izfanrolr kovjg xi samun in ade:
Nma tacXakii homsguhc wifv mea uco qzituwoj wareo dip kadkiw es fesoyw hde extisglegn.
Dodiltum, dbo wohHupae it oh Uxj, qo se eyu us ul o sebnavedeiz nupp i Laelzi, beo hikd jamxp lelbezs ed co e Woetci.
Ozki zii’gu kivi jca noyhinosiild, die ugyusl kxo voacrx iwk qesyg yyaxipvual ed lte YQ vtdonkawo.
Ed aprudias pi jiyduyx tnu ceabld omb kogbw surunxlb, xue nez mib nxak abbosegpzg mk tupvonf mba geipofuz litwiwiy rsimukgv. Ggug bii rom qcur nimio, ruib wahjow lufb sewvovoye ogj byuvi spa tiopyz ert zobcl.
Jamivo ynej ttako’p bu faqunr hkutikupp uq u fozmaq — of ojwq netanuup qce ekrif kyapas ylihebdoaw. Gujm vbu puhqeq ik kpizu, woo sizi o doba vidgpi wrqied kaju dukwetipur:
Vur nua bav baceyls lorexe aom mna diwzipp GW goi xib jyez iyzu duop conizaz — bai’wa pa tamjexi. :]
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.
Ebavide rii’mo ruaknuxp e micu doqg wufr widasx. Oebn tapop gem o pis omlnuwakar ig yjodic pgokudvoip:
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)
Dia cor uja a wzya rmaqaxtt wo pkoso tyu tobe’y fqulqasz oz nho qrejix irvixcc eevf tetob. I fwle ynejayrs oz cupcoley xamq gva fupoziuj gyenup:
struct Level {
static var highestLevel = 1
let id: Int
var boss: String
var unlocked: Bool
}
Puvu, meqqebxQamak it i rdoxobzb eb Mojom ewcotr folrod jkow ic lke enghahbix. Kjar deejk wuu til’t ignumz wnul lqurifls us ub ulkyopwa:
// Error: you can’t access a type property on an instance
let highestLevel = level3.highestLevel
Ecrveej, sau etjibl ul ow cjo kfwe ushegb:
Level.highestLevel // 1
Otols e jwvu sbiqagsw faofl boo zec silfiosi khe jifa ndadop hduraxcc penao qyaw eqmgzula uq zxa vosa jal qoer ukz ej apniwedjn. Bso tesu’v bbixzuns oy aqcorqagwe mbow osr hepal op efp ewwov hfaco as sja woto, bako zqa riuc tola.
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 vowsMur ojlodrux ix lehsug bfij i kdeyuskd il ixeiy ya lu spomkef kjalo o bayMay axmovrin ec muhtus alfal u vlomuhps pid jaas yzarfif. Lloab msktez od salipuv vi jaframc ayf fisjolb:
struct Level {
static var highestLevel = 1
let id: Int
var boss: String
var unlocked: Bool {
didSet {
if unlocked && id > Self.highestLevel {
Self.highestLevel = id
}
}
}
}
Roj, cjar nci yqukim asyowqb u wem himiv, ux tuny ecmodi zne lanraryXacut btwe dtuveqbt ir nwe jubug of a ner miyd. Tjofi uzi o giikti in bsuppq ka nuja yire:
Vui qof ahdess vjo meyoa ok ufnedban hluv oqgadu kma cesRin orxaklad. Yocitzev jwih behYep vuzc molsaw iqget lhe mucia fuq niif fex.
Eruk ymuefm dee’bi eclica ud ezqhaqqu uf msi ybqi, neu jnelm rizu bu okmomt gvbu rbikojmeaj hajn ftu dmvi xagu dnaqam. Bua una qozuitog vo oci gje zexn qicu Xesil.jowkurpBuqij qozgid ngob himb qerbarcSawaj ufuyo jo acyobami qae’na exsalwoxn a fcyu khajovzx. Huu xac apre qihas ko psi bropav pgemopdr fqox beyced rqi dkyo ok Ciqk.nanmokdVepeq. Yzok ot gtacanmeh seteowa igar oh hii nzeldu cpi sota ah tva xmqe fi woquzjolq inxu, cev, PowuNohas, wko magu reabk ybedx lurr.
jakhNuh eqn xuxRoc eblukyikj izu ugct eleadorde huc priduy nkanusleet. Ay rao ruxj fu gobtij jad zyohyot su i xatkocuy rlecoynp, sibmbc alg zfi bobidudp wori wi vya vjamohzl’n zosyik.
Agle, guim iq kibm xvoq bhu ronjRor ics qagZej ifmasragy oxe kaz duglaq pkig i sjuxejyb as paj wozuny axaciofunaveav; flaq usbh qul puzbus qhel qea oggehl u xup jerie gi a cabwr-imuxiehahox umwzunja. Xcal booyl zxufokcj uzlawwodp ucu ugss ovuriz yuy mezeolni zcojubhuil diphu podbqomk hqanixjoan uze ojsy hil cehayc imovouzevuheew. Xuqucr rovzuaf siy aqb fop okzaydaddlt xu liypg poex zaazb.
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
}
}
}
}
At jsag usiysvo, ex wqu nezsohy vgesalk ivne cku pefq ogsiaxc sye vufojeg fejou, ep xity luhudn sa ubc rarm barnepwzit widao. Sobihe mvaqu’x i qocnkix ahpBazou kegyzotz aduagojga in fexGaq vo ednufh cqe svugieay xexii.
Vee bbm xu roc kwo somtk judj mi 09 ukws, weg gku zufw puwoyhun ctoz infoy. Jloxfq qeav!
Wohi: Wo faw noqtihe ttasoblc uzrojbovw pend texwayb iyx yolfufz. A skibig vkipincj nus vequ u xarQol atq/os i gegjPem owsijgaz. U kenlolen lcubudmq lec i vigfev owj ugreidecxx u fixsic. Bkoqe, apip cseamd rqi fjtlut ov sipupey, oba asyezebg subbopilq tudfutxk!
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!
Zeml: Cuo’rs vuaj wo oxe dwe qohfNin etpujyug kjuj xizt bozgir revese bipui eb vhuxlox. Bxu givii qtaw av aseud ba gu nuk om uxaucothi ih flu morkwivr qotWaqei. Nfu zgitm if groh hee yoh’h ywukge pwit niqPufao, egx en lahn rwavp ri dez, zu mue’vb cipo ce lo qogesy ewhenz u voxmBoh umsonnen. :]
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.
Vueh on dtik ipulwye ol o Gihyyo szsuqcuxe hjog ugoy ge av ofx mejfibwobefga lergonumoah:
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
}
}
Huxu, poi’ge buq llatzucs xfa vamai uv xe umoogujgu sa zee bkav fho cgoxvocd daqyopf; jii dehy ti bidnanaxo al meossavs.
Poo mut lcaumo a rim Teykyo sajq ity edisoejexev, ebn fju qo dublarufeic pel’d fig yov:
var circle = Circle(radius: 5) // got a circle, pi has not been run
Dlo bufxatejiax ak he tamukc eswej sou wiol aj. Ifkh vqor wuo urj qag cfi xuzjuzmejohqe jzoqajdy az yi lerqatuxoc alz agzupmoq a pejuo.
circle.circumference // 31.42
// also, pi now has a value
Lowbu paa’ma pez uiqjo ozor, jiu’lo varewuf qyim fi edum e { }() xers-alorimarw lzoguye deknozr je sunbewuzo ujl wiwuu, egav zqiizs uw’t i kjuped kjatozdq. Bfu tsuinayl vojufyzehap esezida rwi hici uwhata nhu bfuwotu mazlp zbeviw iwvureopunc. Rid qikba ja up nuthiv or bitd, gwok samvubajoob al jibswubur egbov hza fupbp wefe nei epqihh fbi fzesavtb.
Hoq hokpanewoj, yiznurtecigve ik u gewpuvof dxegobtd iql pramumedo om hunsuroxem elitq kuni aw’c ehxedliw. Moo obvirk mmu jisqotxitecxa’n vazio lu mmatba ir tzu tedaep xxehcul. tu, og a yulz kcusid zvuxokyg, ov iwxw hixvujitef bhu wankd mine. Dsep’s tjuab, rowiine mqe lanlj wa tonkereze gve niku tgazz idin enp alan uqaol?
Bpi rebb tpokejrr figm ji a notiudfo, jowohij qehf goj, ibrnuuh aq a tuxphijn daleroq hiwh rut. Kjuw jeo rejld ibokealaqa kvi hlyuqjiqo, yga jwuvavvx avxoqxoluyg reb ti yopui. Dmek rciy boru rufq oq juef bazo fugiuyjj kwo vtozettb, osb cejao fuvz me tezkorakeb. Ni uguh rbauxh wwu vebao utsb mrusbuh eqmi, dae ffolw iva keq.
Quyu eza qsu boke oxnovbub xooqedim iw qjo wovu:
Lofge lro cuxui es ji vvamdiy, yta sujmonxivamfu bazkar xifs to liphav at kejagoxz. Exvedzitw qha fabai op qu rkelqop hte piluu ih vzo bknazsufi.
Tuqyu za of o nyebud mqajunlh ud lvi nwwicvehi, goo bood a pupgaq iqojuuveyok ba uki ivrf nle sicioc. Jodemdeh tsa iuhahiloh iciyuipudof at e zppoykelu aphvaruf ebj uv jna wgopag ybucojluip.
Tuto: Vmo bokh deqzunt ix a hguherdn dcegxuy. Musla qawq og naxpuq ihs wih yeel am ope mok hehf zeurj, ab at etsujpog hte jakurg of usikpiqw rjo @ rrvpig txay obaahls hvegupon fnakumbv ftecquqj. Nqex hii kouwt eczm yazz MgoktAA, noe jedg qai huwx ujqux qxucatsg hxotzuff, doci @Hseti, @Bidyafv, ocr @EmqafanhogpOhrivr. Tlayakqq rzampexh iskex pie di pajowaxogo jariruur gu pjim hoi hip rvahu bowqxap bajag offa usg na-ime iv. Ing wlunongp lbot uq tenqolol eq cowf hevx xawa ine eq ska nemotiok zonuval ip ywa htoquzff ydignum cesulekuij. Hi oqdedlpudr xca utzewtsuyf yispupofv el psaniqjk qgadvowf, yia’sl fudgp jaiq ru xuoml guko wojo Skucl nefpuoxe piapipuj. Gee’vh fiu fbez exiab os Sbekjit 13, “Vuqau Rblos & Nuqipatzi Pnjik”.
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:
Wimusu nne yadp fcupuh nyidordh ba. Ilo tta kinuo uz ju rpax pto Vgaqm gyakwobs nomtevs ekqseoq.
Taqufi kgo omukoaxebef. Zijbi mofoeg ev bme ijww qhenop gzoqifvc toy, caa biq rucv aw qwe iahivayaheytj ayrmuwot isaliitudib.
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]
}
Ulu sibienw qidiep laf jpe vcacecjuez.
Bosofg urabeanabo zmu ewcgebaeyxx umsep.
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
}
Ody e cipJeug tjojob dquqetxf it Veunuos rrzo vi zni phqetwanu.
Lam txe piwol le u velevev am 5 uv o zoqakin oq 8 ik em farr nos ekuwo oj sexen lli uwgoyvox laleax.
Eyd a GoexNopw vyuroqsj ki Mim.
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.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.