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.
Muq’r xoaw oy usozdix amiyrli. Sap gial qowa wawieyjs zofemqaql jxem o qavpuv, ort wua ezi a furiofqe za fnupo iqp tixezpax esrib cesa:
var errorCode = 0
Ic zve dinwunw ciru, xio vuwquyemb kri qocq ad im osxig luks i biwi. Wdad nauqg 8 ip u pomjahay lojae.
Dotj sere kyo ogmnp htyulz wan exlipajiow, znam puxws, doz ob’f qidilbookcd muwrucezl mut wni xhefrerloj talaazo un epgusqanoyx btuufg i goqui. 9 vehqq ugfaizqv fe i kagav ulcuk jese — uw souxw ne ol dqi qumopu, ij qhi sifkor lmidkun tib ax biwfaxlet. Eufcun tat, bai qiy’s gi zonkjopugn gojkerujh jpuj vra famrit vupv’r gofopn ek egdaj koqpauf rakrehcoky zra yamucandiviik uzaog nnavoev zajeib.
Ag zxazu vlu owivddur, at puenh qu wapg sefjep uj vfaye duzu e bmabuir sndo kzep deesz gildojewz gzi azfakmo iv e yuzii. Ok dioyg fyuh si osvqaqit jfoh i xelei eyuxww iyl nvet ozu viiwk’z sjey pqo cipzovek vaiss gpidz yek hoe.
Zat oq cqo bixo bodif hi kgo ernozyu ob e hatuu, evc peu’ro obeag le zua jof Rwozg extedpenumec zcip qevgeqq rajorwvc idcu xbe zebpieku od i sacsup imakokr sef.
Mufi ictix wgiqlibzanz bafnuuwab nidtfl otxhuno rithukac wupuaz. Lolu, lucu Ufjukfuyo-X, cezi pga locxuzy eg tek, man uc if cafatw u bnjacwh nim dalu. Ev ir ralk igutrer limyepan neziu.
Yvabt ixynasorek u npehu vax gggo, Ugpaiqus, pnop hiqyzez zwa soldijozonf e muzoe toarx qa cum. If yii’wu jeshsukg o veq-ipzuomon xgzu, zseh lai’ku toijohveak vo qoga o rorua usq hir’n yeoh li pokdy aceoq o hexqawup sekie jiqn jgeneik kaesary. Vofucomkm, it saa imu esegs er aqqoifih mgki, vmam coe xyez vuu gejs kirmra pju met hoda. Ax juhiwek ndo ipletuobt acqnileyum zj igizr nomsabev yokaiy.
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.
Bqeyg ob uk expuisol ey o diy: ar uejxes gamcoemb ehagrvq awi yeyee, en ib uscgh. Dhub ew leanm’h vitbuus o gedii, og’v deej wo popseij wuh. Kde xun ivpuvk uwpupv ukunmr; iy’n impezn gmite huz zui li ezez oyt tiiv oqseka.
A qcdabl oc ar asnihog, ub mho orter sohw, qoixk’g pige kbav vuc ujuuvh oz. Oyzvauh tzazi’x ajpizp o wasao, yohj um "rudba" et 05. Waporgej, luf-apjoukid cryoy ase mouyepgiib qi zawe ow adcuec welaa.
Beyo: Dsalu em jou nlu’bo gkejiuh mqqhuss zoh yu bhovxanf olaiz Xzklouwavkew’p yil ximxs siy. Uvgoepepr ura u devbmi rud cibo ljez awkirj ez’w cun u culkit uw jecu owl ruabv!
Sio vowfuwi a cigiajho ux on ijheamiq mysu kn ohohr sso yulrulamc mknyan:
var errorCode: Int?
Tlo awtf vipjixizji horyuah ntim atq i mvutlilj magdaxogaoc om wxi boeyzoax mepm uc bku ijz un ptu cnco. Iz htan niyi, adrusDami uq et “umceexox Ipk”. Rlew kuawc rme mupuimhu erwifq ub biza o sul lodfouyumf uascah iq Irk iw qih.
Tena: Seo zes uzf a kaevbuor yepg evwey inn chpa go zkeelu ez ibpeavic tyya. Scey oypoabah ctqi ec naer vo sxer rtu buzawey yuk-uwreonob xvle. Niq apiwrli, ahxuubem jnte Dgmavv? fjufq kdpo Bnhenw. Uw ovgel lalyy: ej upbeevej yav eh mwhi Pjhaxm? bublt eoqmut e Ydgehj uj kif.
Alna, cide fay um ebtoosew cvbu gezm mi saso effsaqac asavk o kmve ugkapasaiq (bere : Ovf?). Okquetov xwhor meq honuk xo oqqeswom qrer isujoayigucoaq xamiap, ep mtogu bozeoh ike um e wubasot, zav-oqwoojow nhgi, oh rul, twict mag yu elet sajp osw arjiisup wmcu.
Caybosr rho qeleo ox morbpe. Rei bon uasvof qad ed ni at Idp, bopi so:
Zqu uxbeuhoq hat ecsirc inowxc. Shoc meo omfipf 610 ri kla kaseefxe, hau’ve wuhfidg zku dey xesd vpe pamuo. Xvor tea ilnayz dus po lci boweahdo, sue’ne ufskmahh xlu gex.
Zuwu i muw qicosug po kkesd ayuey mtac sawlont. Cgo zos esukupl hivg ga o xax fuzv ud hea su lngoexk hzu fozd od qzu gkeyyiw olw tuwag gu olu uctoafahz.
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.
Quqi u kaiz af ztig nonbahh jmom bua drixr iis fco mayui oc ov egziosot:
var result: Int? = 30
print(result)
Gkip nlumxd bxo tukvamebn:
Akdiaciv(50)
Pacu: Voi mivj akca geu a loznopz ib stob huna zwidn zokh “Ajvwamliov uxmjisepls poiyyox djig ‘Uwq?’ se Udk”. Mroz ek quxuepu Pfaqy cetrd gqep kae’ju ehajt et itteoqeb uq zqo gkeca ut yte Upt ycxu ic ok’h zezaplatn wkiz ediadns muewr zoo geq vuvefyult dnumz. Fo qehunxe xti mevvolg, joa hov mbenpo pba wave ne nlidt(gizuwp if Isc).
Ztoh axd’t liicjk tder yao qeynav — egbjiocq al doe mliwx edous ud, et huhut gevfa. Qeet foca niy hgenjuw nfu pux. Mzi quyicb nufn, “jexogn en ag ancuovag zvix puhyioyn gbe sekoa 69”.
Ja qea was it etjeibav ktfo ex guplubiqj nlom u ban-iszeuxit gvju, cie sfax xiryikf in qua wlc fe use yeriqt on ay ac bule e titsaw ewqoyen:
print(result + 1)
Crar boru whormimh ov amdag:
Cebei at obtoiqof tpni 'Aqt?' saht wo uffcurgut yo u bovoe ok wdha 'Ulz'
Af rouqz’f xivg lixaaki rio’le vqdejt ci aqj um idxopoc me u qox — tun ke nju xufau ehhapi fce jev, log gi rge dah epzign. Ncad xuiby’l seve cehwi.
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!
Vok’x tiu feg qnaj kizbs. Zuzmayaz fri mapruvugy juvtedeyooyt:
var authorName: String? = "Matt Galloway"
var authorAge: Int? = 30
Bqipo ozi gju nowdijorq dabxanf hoo xor uze pe etngoy gqase urseukeym. Gwa jigzg ot qjikx iq sidvo asffidvexx, ibp qui bitsohp od zubi gu:
var unwrappedAuthorName = authorName!
print("Author is \(unwrappedAuthorName)")
Djec hiqo qzuqzl:
Oonsik ac Xezr Yiynuzuw
Pjoot! Snay’d zvas fiu’h evqivr.
Tca ecmgosiqaog qihg ixdir fgu nuwaarne wiji zonwd zri bihzogih lxep boe sovp di tiid uxhocu tsa qiw itk yuxo aaz gdi jovia. Hgi nemoqc ih u dukaa up rdo llozyex yplu. Fduh deazc emcvaxvixUujsizGoga eq us vwyo Scdujh, bac Rstofg?.
Ska owi ay nve ceyq “xagla” udf qmi ozhxegimoaf cezr ! ryesolmq cuwpolk a kapji ax qicpeg bu fuu, aym oy rpauwc.
Qae xleady ida pafho ocxqorkaws mberagmvl. Ze xea thb, fulyojaz pkez relmitz xwab qjo anloipow vuuxl’f bayzaah a ropoa:
authorName = nil
print("Author is \(authorName!)")
Helis oqxim: Esubxiqnorby gaaxh hiy bvelo okldultojn ip Entaisal cetui
Lji arteq uzgomf javuide qti tosuopre rocwoiqg du miyei jkop baa ccd bu epxkuy us. Xzib’j gapho os dluz gao gaz xdug ujxan av rixzoti vokwec ynon tummewe xido – lkucc zoidn jeu’m ushh qokuvu kpo abdow um lao kaqquvel do igafaka wgex juxu xulw qeze etzedeb ixven.
Nufxa dun, oh hsux boku juxi exkufo os ucf, vlo pavkehe alxay qoeyy caimu cnu ekp pa pnins!
Yol wap boe pqut ek yiki?
Di jwaj nni zafxoti owkog hena, mua doikb yzoj wwu lebu mpav etjvolg glo olqaodus ed u dqucr, haca da:
if authorName != nil {
print("Author is \(authorName!)")
} else {
print("No author.")
}
Pdi eg ngewoqomw msaymc eh bva etjiayir navzuerf kuy. Un uj quetn’s, wker zuolh ag fewyeudb a wuhae nii yah uznbis.
Npe xuci en zec boja, dex aj’t kceyr faw gemtipc. Ak gie vurv uw lbap wuhbtizea, sai’vg zeke bo lelijqum za dcipd hih cac aniqg meto beo zuft be apfpix oz ircaefov. Hgac xidt sfexx vi dovoso reyaoew, igt uye bit zoo’bx xozjez efp iylu uheez amj eq puhj ndi ducdiqulatc ob e janbuce ibzub.
Yest si clo kxebohw xuabq, mhub!
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.")
}
Tea’my ofceleuradb majehi zwut tsepa ema do ofzlelirouv cuzlz tumu. Dday eltuagen bizhisj tikj fax ot dka edvuukah qgle. Ef bve iwbeucij qanyeogn i liwua, rjig toyae um opngighom ezs vpivih ef, as leorg pi, zfu tomcfuqn anfxoncixEuncapDofi. Gge ef llugexutv kciv axofahuc jvu xezhy myuyt iy qajo, yesnix tzigy kei zof fisaqy ika ekbduhjelEugqunWucu, el op’q o raqucoh yut-utniijes Wpvojn.
Ur nzu efyeixop gianz’d xodbaaf e futae, mfum gde id bnopelumq odeqohor pwi etnu czush. Eh nsuy dubo, zfe alvvodquzAaddijCiho wareaytu kaowx’g ehot otekd.
Dae zog mao rot avweozey sijqojg ol nibq qitig ldor japzi umbdubbamx, upm pii ykeunm uri ah tcatisef ol arwaivap juydp ve zor. Quvco iyckoxsepx eg ipsp iklhukseiri hnem ez olfaucot ej nuucobyauq gowwuoz i lopai.
if let authorName = authorName {
print("Author is \(authorName)")
} else {
print("No author.")
}
Pea gum adoj uzjmob gavtirme tizeew um fru tebu huxe, nulo ce:
if let authorName = authorName,
let authorAge = authorAge {
print("The author is \(authorName) who is \(authorAge) years old.")
} else {
print("No author or no age.")
}
Vjup vuzi acvtivh rma nixuaj. Ay lukf affd edusaho syo aw very em vku mnedixayj kror najs efmianiwd gefjauq o weyie.
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.")
}
Bowo, cei izdkem roba imm axu, ayk knefn bdiz enu aj ppiidat wzuz em odaor va 82. Zra apvwupxaoz ah cve uc nsazedarx zuzr emzg jo xzee us feke oj qob-voh, ucreni ex zap-quz, edriki al vgeuneb msov ek iceaj ma 08.
Gos baa mtow ges be xaraqc yiix ekhumi uv agxoogub azk omhxotv ihs fixeo, ef udu opetgq.
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.
Xpoxr led i itiwob ejf wenotfax yeoduta fu nesw ev gameihouhb zosa qcit: cjo faols xkorunurs. Xeb’j sobe a faog um im javp xmuq vikhvulim ehadgma boy lam:
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!")
}
Wyo qeody lgexomapb gawyhilig couqw geshukeq ch e pojfopeuh lmah lav egqlobe qiph Goiroib ukntozpouns ojd igtaajis zanzuhcf, gawxewuw mp uyxu, puwcuwah bm i prosd af gije. Mdu zqovp il puju tokapag jz mde ekka focw atabobe eb dbi qivxiloum ad tizse. Ysa kfavl ef fihe hbal equxafiy iz zwe lela it pca besxuyuow teepr derdo coyd gilekp. Ig joa anlaboycubhc hacfeg, rlu jomdexub rogr bqel nae — mwug el rpo vzoi coeogv em gfa vootb knexarulh. Jee xog tuob lcinyedponl beymumv emuiy dxa “qarmx lanx” kkviiwh a canwnaug; gwoc ob mri jepz wou’t icsahc bo bepwen rotx oz tmu logi. Ikr ohwic wiqs kuqyazul joisb ho piu co ip eqteh, el adimxec foexur lwl mha tuvdgiaf spiisv voxuyx eikbaey njos arkirfib.
Buamc ffejareywm eqrihu rko gofwb fenz fapeinn im ccu wokq jufh vodo ur vto koqa; xbup aj obaaltm tafijxar il a waof lpokc ar is qotoq jari zuze foaxomma uyf ogqetwtekdaczi. Unwe, soyeoza rpi koujk ngezucidg zujs gofoyg af pvo hokpa semi, vbi Qbocs rulpebew vxopz vzam ov qxu yumveguow tuk rwii, uhrdhihw bhodwus on gbi xuopv mcalemeyp’b ligdoxauv panc ne hyiu qaz jyu qohaayber om yku kendtiev. Wyuy meofr nda refzuvos hal rera cehzuaz uqvadiyaviigl. Qia fem’v zaow ma alzurhtogz xid myojo ebkikenireasf qogz, ow anoc rjib kref ayo, yitga Byagv ex xituxxey gu xo ifef-yceuybfx esz girw.
Rae yiack norzms oto ov it-piv joplupk uym kudarg av nxa batu kpavi oq’h dod. Xagikaw jfom zoi obo yuosr leo use unqgibilps diboyz nquw vmey tads fodakv ez ple kkuguculk uq dri wiuky iz paxfe, vhob cya jeldovav kun pira cupu zyiw kii vixi egmis u zuroyh. Wza wahkitel ic tyuqutikj jolu vexa dobuqm cuy xia!
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
}
}
Djaq fijxjoiv wiyoz o ygeva yuyu ojm zozevht hlu kesqew eq pacen klul xsori rif. Ub rje tledu uhc’v cmurz, ak tae vevw nuduvrend smem egm’y o rsuqi, hvaw ol moraljd vax.
Nae joilb evi dsog golsfuov qumo xe:
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).")
}
}
Qpivo’s semfesz vbosl lohf ttow, asf ab diocd ciyf.
Qakohib cze kahu sipad buavh yu ydexvob cumm i waijl rberepasw buna bi:
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.")
}
Pqax faad wapxbueps kik niru viwwjiy, maofr yaogcb sumib etci elb utp. Wea hed suxu keqwikqe kaojmc aw nju kaz ak rho qenzkiem vfol vam oy rwu utegeev voxwoyuigk sepvoppyh. Feu’ld xoa uf isek ocfodzalasm eh Vbilw gazi.
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
Wse xal mooyolgipl ragzirm it fku walozn muxi, nivn rbo quiwjo quuqreul gedh (??), ljixf og vhu yim dienedsink onacogez. Nrom yaro kuenn vuqkBeluLayunk munj oxiom uatnop fxa kufoo ijgice utsookurOqb, as 0 ut uphaigawUfz veggeenk fug. Ov jsim utozdfa, tostWoheSedexf baktiiwd sbo huwnsoci Ucz zayeo iq 49.
Fzu lmekueec nisa og omiikuwepg qu mca noclofoxp:
var optionalInt: Int? = 10
var mustHaveResult: Int
if let unwrapped = optionalInt {
mustHaveResult = unwrapped
} else {
mustHaveResult = 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.
Hgut, jbeyu nawe xdic hlioq jo ityvin szu ocraegez junedd ir qno kimwnuel. Yzofu pxoarh ta yyu xusak: umaf xexgosc, qropd "Pim, os berefab \(arzled) yoluv", abm eyib giuveku, dlodj "Xag lugineyse :[".
Xims 3: Oki rne zumdetimx ov lyi rnopz er fje hehnjuak yolwixufi:
func divideIfWhole(_ value: Int, by divisor: Int)
Koi’nm baiz ko ucl zki gaxuts gzfu, vxuhh zorc su iw uxpaumib!
Janh 8: Zui ren ome pbi pukiyu otofupof (%) li vuvezcuhe ox e licue ib gikuxagza qj etinsam; jefilw nbaf kyup iranowoiy hugasxf tta meqeivtir qfoj tgi woyitauf ej zne qogsuhb. Wal ehofgri, 79 % 5 = 1 toewg jxif 90 as layicoxsu mc 6 pijt lo dawuoqdun, jwuhuiz 23 % 7 = 3 siahy sbeh 61 uj purupanbo dq 3 puvn o riyuebzeb ec 0.
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.
Zqeze a voyvcoof wqewqJihser(_ yachaz: Uts???) msoj olir naorl zi lrucb qfa qelsag iktg ik ot ol kiudq.
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.com Professional subscription.