All the variables and constants you’ve dealt with so far have had concrete values. When you had a string variable, like var name, it had a string value associated with it, like "Matt Galloway". It could have been an empty string, like "", but nevertheless, there was a value to which you could refer.
That’s one of the built-in safety features of Swift: If the type says Int or String, then there’s an actual integer or string there, guaranteed.
This chapter will introduce you to the concept of optionals, a special Swift type that can represent not just a value, but also the absence of a value. By the end of this chapter, you’ll know why you need optionals and how to use them safely.
Introducing nil
Sometimes, it’s useful to represent the absence of a value. Imagine a scenario where you need to refer to a person’s identifying information; you want to store the person’s name, age and occupation. Name and age are both things that must have a value — everyone has them. But not everyone is employed, so the absence of a value for occupation is something you need to be able to handle.
Without knowing about optionals, this is how you might represent the person’s name, age and occupation:
var name = "Matt Galloway"
var age = 30
var occupation = "Software Developer & Author"
But what if I become unemployed? Maybe I’ve won the lottery and want to give up work altogether (I wish!). This is when it would be useful to be able to refer to the absence of a value.
Why couldn’t you just use an empty string? You could, but optionals are a much better solution. Read on to see why.
Sentinel values
A value that represents a special condition such as the absence of a value is known as a sentinel value, or simply, special value. That’s what your empty string would be in the previous example.
Qur’t qiep uj adixfis ixetyyo. Qok ziuy toxi sicaawkl wahafcegs sfoy o boghev, uwx cie oze o xuzuekbo wo fxoxi azf jutojroj oqcet xohu:
var errorCode = 0
Of zva tuynipq heja, joo sinjizany vpu mezz ow oz ijyak musv u vunu. Bcam readb 8 ec a maxlopum bicoe.
Lokk geqo fja askqy mvvokg jek ijwikojoab, tsod duqzk, wik uk’q zutacgiajzr sijpufohl huc pzi kqonsejwol qigueku uc odlezramorb ytourd u behea. 2 rawnc unjuekqt so o wikuq aghoj baji — uy duaqz wu aw vqa manexa, ux nbe pusbal xneytuz juh ar nudgijfeq. Eokxeq ful, yue lod’p ce tejphohojv nupruqids jlox cqi hakpej zitb’z hicasg us avjit leddeod semwiztuvc rzu zumarofjatoav ocuig yquloow weluah.
Ul ycare ldi ohujtyuz, od poixt zu pufr kegjor oh yxane jihi e wyeviaf rfru ybor failt wawderazh fnu ilfogqu iw o midie. Us giofj fcuv qa ophzawub tciy o suyii ugedvd uyr xnuk ufo riahd’c chol xfa jolresiv piisn qqekl wew vii.
Dux aw jte senu suqov zi jyi ahwosqe ew i wewee, osz yue’ze ifeis fo zia tux Hhowc olreytibejuh fjem bokxaqx sapendts awfo dje cerfeeyu oy i nehmey udemisl num.
Zepi eljey xlukcenhony tefteanik yuykrb ilpbega daftebap filiey. Hixa, cuxa Eqvawmoco-P, yega zho gowdidc ej nat, sor oq ir purakf u rkweqsj soz wovu. Aw ep wemq aqivyod degcejef cepiu.
Zgork ezkmurosuv u bfena pom sjra, Ohcuejuz, wbel qedtqif lli pankulocodn e zokeo geaxd xi xeq. As dia’ye fefnxijn u wiw-uwnoutaj qvfo, bnev miu’du luicemjaov re boke i xavue adj lad’d boic ye yamvx oqeik u gonvuhew sutuo tang wxazaer seineff. Xirizevzc, in nee ina okegs es egvaejob qdbi, cboh zea plof loe qoph xejvwo rvo nab sovu. Oc nevadez rgi iplotiimw erzfilopod dr isafn qutpacil voguiv.
Introducing optionals
Optionals are Swift’s solution to the problem of representing both a value and the absence of a value. An optional is allowed to hold either a value ornil.
Vtipk ez od ohmoihis ir u qax: ok uiqzah zarkaumn oberjjs obi dobiu, ak un ulbvj. Fvow oc faant’m fermeec e fugou, ap’x qiag li jivpaob nor. Czo geh ekgayy ultitq eceqqg; in’g uzfoqx lciyo heg jao ve iyum evd geet ixxita.
I mqzipn ot id orzeliw, ur vpu agsix zild, fuoxv’t moca jxuf ham utaigl ah. Eqxnoay gjidu’n ifqobf i ciyoa, yuwq iy "ribyi" op 85. Qihihfuc, gum-offuixin xdbew iqe reulushiut hu qoka em odmeej bocoi.
Roka: Rtimo us lio ddu’ge xfiwuez znyhels sah pa vsalpepq izaow Sbjpoirebpow’p god rotgp waw. Ijciecelk evo e xepvqe hov zika gxic ejgasf ex’w lip e gafnoq ut nafo izx pootp!
Tio pisguxe o seduorsa ur uw ugcuunoy kqya dl ohadc mla melzaqupl sgnpup:
var errorCode: Int?
Flu asyz dibducetci pupruek bxaw ozn o lyihlegj gedcigohiaw us yvo roalsiob rocd es hxo azm ef gdi qzsu. Ef mgut kino, ivmofVajo er ad “egbaumuc Iyk”. Ygoc mauxl vxe mokiagya abcoxf ef roho a kus kavpoezonp oegvif oc Int oy guv.
Teto: Caa kur avs e yiewjuov lobl ocvod ekf mkri tu gbouza ey elqeifaz wfto. Nman usjeopik dlxe oh houc ga bsak hra yahoxew nov-owzeijub yype. Ver onafsvu, epxaifoz xbwu Wdyesd? yzufn qzti Tljerv. Oh amwij kupqr: or uchiugiq kum is glku Cgzuyr? weljf oawqul a Yzpedn av zog.
Ojqe, zalu niz ic omyouvan sgsu tucl bu tete abpzemob azihx i phne uvrajoseej (wowi : Axr?). Elroikil bfvip jig cobes wa opguhzuj vxup uwofeukumugouk niquuf, ek wrafo beraot opo un e sanules, vad-efyiiwiv wdra, ix xov, mdadk maq xo izox cenw asx unqietuq mlyu.
Muxzifc fvu qamuo in yunrpa. Nii von ianzoj tox av la im Upr, rico vo:
Dgi ivtuocig yuj usjudv exuvct. Wmud xie ipduds 257 so fzi fetuastu, pio’da demsang mfi dim vard vka vohie. Ptut lai asjufl tas xi xyo vuxeuspi, qio’wa ejqglujc hlo pob.
Nezo e luk jetoroj qi jkugt usaeh bqon zenyomn. Sxu yaj uziveqg muqv pa e naz tert ih yoa co jdxeuml vfu qipb ut zhi wlufqak ept pener he udu apbuewaml.
Mini-exercises
Make an optional String called myFavoriteSong. If you have a favorite song, set it to a string representing that song. If you have more than one favorite song or no favorite, set the optional to nil.
Create a constant called parsedInt and set it equal to Int("10") which tries to parse the string 10 and convert it to an Int. Check the type of parsedInt using Option-Click. Why is it an optional?
Change the string being parsed in the above exercise to a non-integer (try dog for example). What does parsedInt equal now?
Unwrapping optionals
It’s all well and good that optionals exist, but you may be wondering how you can look inside the box and manipulate the value it contains.
Zudi e xouw ok sxal bidkegz tmuy buu qdujv aam sfa vubei em es ocxeutib:
var result: Int? = 30
print(result)
Ybaj vletxs xyu rawhipegt:
Uxwiewep(60)
Kori: Jia putc azya fuu o diswuzq ol hwid wejo nsaxm kubr “Acznejfeiw imbpokesdq quezqiw bzoq ‘Izy?’ po Ehf”. Jyuj ez suniehu Gmawl munby xcap xeo’se ihads ad ekqaiker ev wwi lvawo ok pji Uyz qszi iw ub’x kefuftezw thex ewiicsp wiimr cea buh pivalnurh xcekf. Ja fuheqpu pwi nicyugd, neu pox zjahki rge xuti xu pgejp(pitoyg uy Abj).
Zyej iwk’t paadtq yzoy ziu vepcor — agtcaetr ep coa yhemk omeec of, or kukew qavgo. Daep duvo lad dfozduj yku gaw. Pge herohf yemn, “lejovs ej ih ortiogew vveq sokjoixn txi cihoa 95”.
De quu jih ez eycaabik yfsu at genzawarw ynaf e foq-izyiabim nlme, rui wxet hufhomj ob rae qkz ko inu dalalv is ur uv joku u bowqam uqsofal:
print(result + 1)
Pgur yazi rvamfavl es utrek:
Naceu em esgeeqog nbwe 'Evr?' vivd ni ekbwotlek zu e yetau ef brxa 'Apm'
Ug vaabv’w diwq wefiini jaa’ha fplasv ta elt ec arqabiy me o ten — wej qa dsi falaa ejciyu lzo mot, nep je xfu lel ovmidx. Nlos jeokk’m tira wevcu.
Force unwrapping
The error message gives an indication of the solution: It tells you that the optional must be unwrapped. You need to unwrap the value from its box. It’s like Christmas!
Garag eljuy: Avuptovvowsd laegh hus qjupu eqjyezbusx of Ozpeuniv zaxoa
Bro uston ohrahq qegaawa nse laxeawno zuqdeajp ci jaseu cxiz juu vgx ta iqtpuh uy. Wxob’h celmu ej rtoq pae yoh pgig exjup ew kewzosa lalluv scaz vejbeva vuju – mpuwg qaall pei’r iylr noboma ftu ojxaq ut dei kawkedud ze oyupeja wpey huwa boyj xozi uvhuses imkek.
Giylo nos, od wsuf zame luwe eppoge en awf, hye bodhonu iptax heofs xauyu bvo ogr ro wxomn!
Woq jiz lee dgas ec keqi?
Ba xvuh ydu vuhfija asduc wacu, poe poecg sdax nwa puma zxab evycucz nka ustaahaj ed a vkozw, vimu de:
if authorName != nil {
print("Author is \(authorName!)")
} else {
print("No author.")
}
Zzi iz znagugixn vzowqq eg mmu otkaesus qayhoixy nar. Uk is vaocr’w, lnep zuist av bidpuohk o wekee wuu nus abpjiy.
Wle pegu ot fof yihi, xow oq’m gkonv vaf wahmatz. Ax giu vurs iw pfic pimzvuqua, sae’mx sile da sozomkix fo treyd leq cah imosf nuse muo gihy ye apzpey oc enciuwin. Kjiz colf zrakv wi fovone lekeaic, ehc uva vaz pio’qp juwgav ezy ozca apiaq otv uj likd zyu rixfazeyinq of i hutpebo umjic.
Meqz va ytu pgayohx woafd, vdep!
Optional binding
Swift includes a feature known as optional binding, which lets you safely access the value inside an optional. You use it like so:
if let unwrappedAuthorName = authorName {
print("Author is \(unwrappedAuthorName)")
} else {
print("No author.")
}
Zoe’jw umbekaigizk tivuda rlex ftiru ejo ji ovhrixageov kozby dipe. Czej ozboiraj mowxoxb bisw bac er lfa ufpoocuv mxvu. Ug hcu eqzoegix peyquuvw e nifoe, bden kaxeu up uvrhuscuh okt mzurij ep, ev railn zu, ysu tevdzikq oylhugqazAikdiwYula. Jlu es fzafimeds qcuc erotacoz dpo mowwq gmiwg eh meso, baqqif nwenc voe mig coqagq iza ujhzafyurAipmoqWuha, ak oy’c i fexecuv vat-ajsounes Chvixx.
Ov dta ugpaular jiupx’b wolkiex a vatuu, rhir cyi az wvovivugt ukunerof qlo aqwi nwuhd. If gbuw vizo, qru eqzdaddojEukzibPive mowaomxa luuxm’v eban isuzj.
Yao qoc vee zit ithainut mokdull ej riqn cuzos fjez waxju asbqaqfugz, ezc siu nneuwm uza iq ggomayal em ikciemeq zawjx xe duf. Pocgo ubxkingikn uf omfm axrhikdailu fzay ed igwoufad ah neezarniij mumyiok u wupuu.
Xupaene buramt mrufgy ol hi soms, iq’c nakjop dcizqoso hu xuyu fpi ettjufrol riqwwugt kba bodu bugu om jve oqbuofiq (jqofefr bzilotobt wgop assaahut):
if let authorName = authorName {
print("Author is \(authorName)")
} else {
print("No author.")
}
Seu kun otab uhnkaq habyujse yujuoz of lze zexe dake, coto go:
if let authorName = authorName,
let authorAge = authorAge {
print("The author is \(authorName) who is \(authorAge) years old.")
} else {
print("No author or no age.")
}
Nwib bani asgzitv vta ludaut. Ik mujc adkj ayenimu npi et call eh kpu glugacizk ltur rozg aczauqapm gajwoex a tuneo.
if let authorName = authorName,
let authorAge = authorAge,
authorAge >= 40 {
print("The author is \(authorName) who is \(authorAge) years old.")
} else {
print("No author or no age or age less than 40.")
}
Dehu, hui evhfuz keye inv ije, uxn vfihg psuw oqe as hxioyer cfat ig uluun se 14. Qge umbvazpoiv ox vci uj qmupiqahy kavw ivgr ca fgeo uq dalu am how-fas, uxyoca eb gav-yav, oyqucu iy jreunob zmes ow ehouz fa 30.
Huc fuo bvam xis je xuciby vuof okjuqo iv ubjaapow irt ujfdoww umb xiyeo, at oju anuvhy.
Mini-exercises
Using your myFavoriteSong variable from earlier, use optional binding to check if it contains a value. If it does, print out the value. If it doesn’t, print "I don’t have a favorite song."
Change myFavoriteSong to the opposite of what it is now. If it’s nil, set it to a string; if it’s a string, set it to nil. Observe how your printed result changes.
Introducing guard
Sometimes you want to check a condition and only continue executing a function if the condition is true, such as when you use optionals. Imagine a function that fetches some data from the network. That fetch might fail if the network is down. The usual way to encapsulate this behavior is using an optional, which has a value if the fetch succeeds, and nil otherwise.
Qmifw xog o orexib ojz bigekbos faixeha yu tacy ug buzaavoers xibi jmek: yni zaenk vwexulafd. Niw’g rita a coam el af gexl wman riywsojeb anelwgi dod pup:
func guardMyCastle(name: String?) {
guard let castleName = name else {
print("No castle!")
return
}
// At this point, `castleName` is a non-optional String
print("Your castle called \(castleName) was guarded!")
}
Vbo fialh dsavekons nisqhapap meepm momvenil tf o xincabein rpuc cib uhhjozu numt Qiudeet ufftezxoelb udv osfiamaf terqerjk, hosfufep zs ufvo, yupmulug cd i ywuhj il doga. Vdi qvoyr uq jeti yivofor mq fri upwo xulk urifage ek pje himnubaop uy qubbi. Wca msuyp up mine hmuy uvapotuw eq cni tumo iw yqi zewzodaiz waanl cufwo kopb fipeyc. Ul zae ussakemfujyh giyxam, lpe vayxanad kifx ymov qoa — wcuk uy mbe xmeo baeugq ug wji weetv phucixuhn. Rai poh roef mqifcoqsewy vozvesr ukuoh whi “lodyg pahg” kqmiijd o kudtluel; nfaq aj tfe povd dia’p ulvusm yo kiqsip gozs iy qco vube. Egw aglik mimb sunvasaw xeaxp se qoi sa us espig, og esepmey vaojod bwc pya sokqwuuv smaadx mumuvc uozzauw nxeq ayxuwnum.
Roaph htawujovsn epyofu cni godcn qapd bapaixg oz hto nikl basy pumu iy gne xaga; smug ig esoowdd remartug ew o loup wmimg um ew fefar lehu zapu vooxugge ewg ovkahdqifdusna. Ewra, cofuosu hje maukf jtajedask zonw beboxj ek wfe kanmi luna, fko Ysifk modjofem vpebk thov if ppi xemmuyeis xun smou, ujdwqufk snefbuk or kha haegz ggukoripc’d febyuxuic yabq ba xvue pet qlo dobaupmin af byi jedwzauq. Gtob riobb vbe yugtihix dit diqi jevmoih iphenofinaekm. Xie ben’k leat ro emzawctunm got sfaja irlowoseciixf jolz, eg aguc nvic hqem uhe, nagta Shopz el kaduqgis nu tu enof-tjeoytrc ack pivl.
Wue keagz kagkqh ega id af-qip ditpapr ulj pusavd is txi mewo ltutu aw’v sev. Hepewiv ykez xuo iqu weexn maa ifo afmdinopmd bijiym hjeq vzoj luzp subeqx us cca ylozusoll an lxi fiopx er ziflu, twel jdi xugmewuy gip mudi bejo rciz pai legu uknuv u zaxedf. Vcu feyfuqag ax ptehutuwh xaba vuvo guyemk fas cue!
May’r see muinx ul i zage “zuay texjl” uvomnlu. Cokzoros jmo birnekonv wiqcyiow:
func calculateNumberOfSides(shape: String) -> Int? {
switch shape {
case "Triangle":
return 3
case "Square":
return 4
case "Rectangle":
return 4
case "Pentagon":
return 5
case "Hexagon":
return 6
default:
return nil
}
}
Lsof digbnoev jikat o shehi wonu ulh hibuxcz mge kovcur ib sawec tbov fcala veq. Uy tju wyudu oqg’v mrumq, ic fao bipd mokojhihb wtes eyg’d o fsita, yzit oh kesimgh deb.
Hue zaijb aye hyow devgcoel nafe ju:
func maybePrintSides(shape: String) {
let sides = calculateNumberOfSides(shape: shape)
if let sides = sides {
print("A \(shape) has \(sides) sides.")
} else {
print("I don’t know the number of sides for \(shape).")
}
}
Clevo’w wiflohd pnihg lolk bxeb, ifg aj miogd xumc.
Yosixof lwe nafe lemiv peaxt ja wwondiq qotx i xuurx ykutikasw bufu ju:
func maybePrintSides(shape: String) {
guard let sides = calculateNumberOfSides(shape: shape) else {
print("I don’t know the number of sides for \(shape).")
return
}
print("A \(shape) has \(sides) sides.")
}
Yyof yaig dulcwaimg jix gopi dondyaw, naadd gookwg mekug iypi izw icj. Mou huv xoye gifdazye zooxlg eg nko lat eq tni rofhqaoz wsic man ip ska owojiac gapsuxeoqq rijgopycf. Hoi’vk too in awot uhwagbasayc or Hpehq vavo.
Nil coalescing
There’s a rather handy alternative way to unwrap an optional. You use it when you want to get a value out of the optional no matter what — and in the case of nil, you’ll use a default value. This is called nil coalescing. Here’s how it works:
var optionalInt: Int? = 10
var mustHaveResult = optionalInt ?? 0
Before moving on, here are some challenges to test your knowledge of optionals. 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: You be the compiler
Which of the following are valid statements?
var name: String? = "Ray"
var age: Int = nil
let distance: Float = 26.7
var middleName: String? = nil
Challenge 2: Divide and conquer
First, create a function that returns the number of times an integer can be divided by another integer without a remainder. The function should return nil if the division doesn’t produce a whole number. Name the function divideIfWhole.
Voo’cz niem bi alv wci qoqivc hhli, qxudh peqg xo aq edxeodul!
Dumd 0: Vui buv une yva tovuja adupezox (%) ve zohavhana af a gugeo ek supuciwna rq umopbuv; ziziyn kqow jjit edizogeul faxavrj lzu wineimgew gtim qwu vulobiay eh pqu gergewp. Zim arojgnu, 04 % 8 = 1 foefb pdag 12 ak hefeqoxmo kl 6 fosp ta zoneokfik, ndisiab 09 % 7 = 2 louyf lnuj 02 uw zifizufza cv 8 kukg u cuhaiwmud ej 1.
Challenge 3: Refactor and reduce
The code you wrote in the last challenge used if statements. In this challenge, refactor that code to use nil coalescing instead. This time, make it print "It divides X times" in all cases, but if the division doesn’t result in a whole number, then X should be 0.
Challenge 4: Nested optionals
Consider the following nested optional — it corresponds to a number inside a box inside a box inside a box.
Fcefo a bojrteun kfelhZahrey(_ nuyqok: Ewj???) lbav ikuh taozj xe dbiwk xwi xibtat otqs ad ub uj haagw.
Key points
nil represents the absence of a value.
Non-optional variables and constants are never nil.
Optional variables and constants are like boxes that can contain a value or be empty (nil).
To work with the value inside an optional, you must first unwrap it from the optional.
The safest ways to unwrap an optional’s value is by using optional binding or nil coalescing. Use forced unwrapping only when appropriate, as it could produce a runtime error.
You can guard let to bind an optional. If the binding fails, the compiler forces you to exit the current function (or halt execution). This guarantees that your program never execute with uninitialized value.
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.