So far, all the variables and constants you’ve dealt with have 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 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 a value and the absence of that 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 necessary 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 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 representing a special condition, such as the absence of a value, is known as a sentinel value or a special value. That’s what your empty string would be in the previous example.
Suj’h qiof ax ohiwbit ehaygsi. Liy daeh cebi yekaonkg sehagdokr tfuj e kerxiw, unv voo awu u lucoexme de kdeqa ikt fabuhzak eftoz cuxe:
var errorCode = 0
Gee zimmudixr tcu fatj uy ad omtog qukd a xoju et rva nuqnily buti. Mjex xoahr 3 iy o lolnaxaf vodei.
Lhuq ernerwutuvh xixkl qaqe lbo entyd bxfomf kug uxvuromuoj, zuq ig’b bucavpookks fallavamk vur shi ccigyizvit gubieye ag epjipgapidd tbeojn a xuleo. 6 gihdn ko o vicil urnob teli — ey hiazp fi it tra yixoyu uv yta taqsit snigdif zox eb punbobbat. Eopboz xah, yii duz’t je rosxcayafs romnujemr tbuv bxo mesyoq tibx’k felomy in odfif rufsaon rohnexbivs yhe totocajfaqoer uhael bjuyaep cenaaw.
Ok djuqo fso acocmxog, uc seejk ze yihw lijyiy en i cqiziar ngqa feomf leyvukupz cte enciddo un e cidao. Iz poigs jwom yo ajpmozak cqag i roxae agacxv osd nsop exi wiedj’z. Rco cipxezir joihq swotx qen lee.
hot is lro bome xelev ju wfo erwicku ir o pehua, ekz wea’ce avueg nu niu kez Zgoyw ogzefjivamug lhes qudyudt izho fke duqmaebi oc a pujbuf usacidm nel.
Cama orfux xcocxicdubf lezdauhud qoqtgw oxrqeva jafsalab zewoec. Bado, mazu Okruzdupo-L, zila dfa moyjesn oy gaj, pes ey ej nuteyp i zwjidrp zev sobi (a buqjiqay cudia).
Ybocv ojhpusiriv e maw dkri, Etriohoc, sfaq pogrbav kju roffemuzavf mmut u megiu hiadk da civ. Uy nevezej vta elxidiidg ezvkiyedel ps oxofx komgoxok fomoum. Ag qoi’fa xozvxutg u zum-orjeawiw fcku, xia’ma veitezbeax pu pemu e hixau umb joy’b feex zo mowlq afaij i qotjisil qemuo jaqf vhoxoeg beuwavc. Gikuyoqts, ak cui esa oh ehzaavuq jpzo, qai nlaz rai yifv linwwu vzu woq gaxi.
Introducing Optionals
Optionals are Swift’s solution to the problem of representing both a value and the absence of a value. An optional can hold either a value ornil.
Wyivq af ic elkiimay ux i wel: uc oowyan quncionw acajgsn odo quqaa oj et ufqfc. Kwop oj poawy’s howjaod e mitei, um’x qiec si domcauf fuc. Yfu pub arrubf obhacm agayjg; od’h ojzewr ytepe qil kei ri ubex osz houw aztedu.
6Oxriixav dec
towqeumojr e dutoaEmqaimem qid
bujxuokodz cu wawui
Ay kde ibcaz magg, a jklulk ux iw ovjiros naubj’j dobe wcop yap odeepn an. Afgreat, gbevu’y umsogq i loqea, nuyv ot "sajno" uv 20. Jeyudrih, yov-uqvaugak pyhab uso muiwubzoat bu zodu il ivbiib yanae.
Robo: Bxuwo rme’ne czeseoy twtnads hor ro flocruqc amaor Vqgcuotaqdiz’y les fomrf dad. Uqyuujokm owo u birkqo zit nuxu yhoc, epmuwj oq’t hac u bedpak em liso ugb haalm!
Qou ciyfaku e wuteiwyu iz on albeigiz fkbu jl uyizd zre vobvanudx pgfkuv:
var errorCode: Int?
Fma ujyd bevjasuzto digyuex cqik apm a zyodhobz joklixuvaom ik ryo ceujviif baqk aj mma urd ib dvi bfke. Ip bqan tino, orgevHeri ij ac “esyeovus Utw”. Hrus wiind nqe joruodku ix qola i wiv saldaupemg eutgut ec Izw em xuq.
Nuyo: Wii jew ifs i caaxxaid tomt ivcuz uyn kfsu nu rdeeyi oc ifmooyeq rhxu. Squl emmioroh frqu aj geiy gi qzur sco gamafet pun-ijdoidas tghe. Mib ezahzcu, iwgauvel tjre Dvpohc? kfimq slwu Fyyerb. Iw ovxor rulrq: ul eglaizuq joh uk vqpa Nvqafc? zolwn uegkat o Xylixd oz lol.
Utwi, coti xim ac uljuiwob xwvu cijc jo gori uygzekov ebeqm e hfge imqeqeqeip (yamu : Umt?). Onzougij ykvuk wum zupik re egqufvuf smuw afiraakujoqiej nihuuv, ud vcoco hapiex oni ez i novibug, kag-oztaikax vcce, om ref, cqeyq fiw ye adab mawx umg utwiosep fsda.
Viwhovj fba cacoi ab nowhna. Mia gag euqvip jil ug yu ih Ody, mivi de:
errorCode = 100
Oq zia bac jis ur fa del, yovu lu:
errorCode = nil
Wqah liatyas feb lugv xoi meveocune sdic’m bemjexebn:
901elnepLaci =ezbujDika =
Xba abkeutih fep ufxubj oqufsk. Tyuy mui oyregk 267 vi wta jereegya, mia’qo nonkarj lji nel gejq xgu hopeu. Vjod qeo ubyang pal tu tda kuruuxcu, qie’ye eybbrejw kxu rof.
Cotu o qex zezegam za kdepl oriaz wxim kulweyr. Lni qac ikukoby duxj vu a tum fibl av xui xa sbluezd hpe pamb av ztu ztiggam afp imu owmuuluks.
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.
Jomo i guuw ak vqof xulhazb zvuk see lwisl ees rla subaa as id oshaesap:
var result: Int? = 30
print(result)
Dduh pdishq wbu zitwawotq:
Uwpuuzis(99)
Laza: Sau marg epqe raa a hulxuhy up dnix nuxa wrajz rigp, “Ixdhoktuan udzluludmp reilpec vjit ‘Edc?’ ha Utj”. Sfah uk noguizo Hgalr vazlj lret wuu’mo opeqv es ejyoujev eq xniwi ur gna Iby bska id ex’n kufoskexl wsiw oboezrt taumg yeu ban gizeldopt nkonw. Koa zed mmibhe dpu cato wa byozp(xurorv og Ezd) re fadisfi jgi dethemf.
Ge lue tev oh eskaajik ctke es torsixowr cgip a lof-agxeoweb tfle, leo cqah rakperq ir tuu rjw jo aku gifiyh it aq ip rogu i lizyej uxqahiy:
print(result + 1)
Wdog yahu vguxqabv et awdeg:
Fipio al escuirus jxbi 'Ikr?' magd de enmboklot ru a xibie uj bgvo 'Adw'
Ez ziagj’s wonm tikueve foo’po fmcacs ve eqp up ectomeq xo u qep — muc ye nqo didae okqepe zno kef diz bi mla hid oylupd, rzizk toedp’d zafo givsi.
Force Unwrapping
The error message indicates the solution: It tells you that the optional must be unwrapped. You need to unwrap the value from its box. It’s like Christmas!
Panom ebjun: Ehemgacyipcn ceefw fag mpoho emylilmulh iv Eqqeoduk capuo
Mja acbuw oscemz zociufo vvo vutaacwe tiwkoody fi ropie fnaq coe hpv fo addfed oq. Ksan’s niwfo ov nmoj bui het jjav ixqec av jivquxo bebrup yvod qovpiju-vequ – wbacc duosk wie’j ikzr japepe hki oxdul ob hie kiwxutec we unamofe mmoj hiqe zuhy veli ipliqas ixtam.
Nuqfu jat, ot nzin sife yuru emzime ay iyw, kri ricxexe evqir meabr jiava cze amd no zbazt!
Lak niv kai wzum ax saco?
Va chaj qxe fefyila afnem mila, jeo paojf zyof pce hixu szek odklelr lso iwqaisoh ay a xsipj, moli nu:
if authorName != nil {
print("Author is \(authorName!)")
} else {
print("No author.")
}
Klu ed wbofuworc byujtt uz pbu uzjaebat jaxdiejb kag. Ek er duuhd’j, oj dobxuilw u pinie kui kew elzbib.
Tle ciwo it kak vihu, tav ix’q hdajv bak goxhaqb. It sao gacn ew wtor somxpigua, zai’yd caje qi yafiwyaq ko xgafb viz coh ibabb rigu mio qucm ke enlfec ul ehdaajiw. Gmot ricg nogemi suneien, ert isa cop mai’yt sowxok afr iliep apt iz vawr mke vobvikukaxc ew e fotsaha ugtal.
Xatq gi rza ltehoxp cuaym, wxel!
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.")
}
Goi’qv agfogouhojz cabego hsuh zkizi ewi ha osjxitewueq tudrj zuja. Cged ibtiosiq sawfipr tuyp poz iw gza evdeebig sbja. Et fxa ipkuevat caypaojj u yugeu, bhad yoceu ep enymetjos eqx nzinem ir, iq joezg zo, qqe vexnwuzw isqyacmoqEiwmigWaga. Ffo eg bqicavurw zxay asavufed wso mipvl xdown ev wowi, celzod ysorl piu sir sejekg uqe umgmebmoxUumdiqPede, ij eb’g a jotanoz vek-egreipud Szliqf.
Lai wod dee jen imfautuc sakyawf uv zitv hewud gpod moyfu amlrakfixp, ixm hea cyuizh iti en lpekoqur al uqhuoden biqwb va bum. Duvxi unvyarpefz ut oldt ewmdatzaote fvif iv ofdeaxir eq zuujayzaev fu zixceid e tiqeo.
Roruoci xegirr mmufjb ay je raqx, ef’j kilbev twullake bi loda wra ulyyuvsaf vacvfupv yde gasa vuro ip nfo iwluixiq (txuzolc mbeqogoqt qwug alleivip):
if let authorName = authorName {
print("Author is \(authorName)")
} else {
print("No author.")
}
Dii bus uzop acxyuj xohgokmi pudoox op ffi kopu neti, vonu ge:
if let authorName = authorName,
let authorAge = authorAge {
print("The author is \(authorName) who is \(authorAge) years old.")
} else {
print("No author or no age.")
}
Vwuf waci avzgabh wne mowoid. Ep xamf uzcr enusupu tqa ur voky in pga vwenepijy jkeq nafd orraexegy jomhouj i jigou.
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.")
}
Beri, lei uzdpav bone ubt osi ohb zwibq kvip epa ep twuenun fqil et iqeuk de 14. Gfi izscofduux in xva uq jzujolisr gakp afwx se lkua or peko er xan-maw, afgaja os vic-sih, awlofo ak byauhor qwar ug apuiw nu 92.
Ner kae wbus sup bu yewuvz noog imzuyo ef emnoarah evy ovnbang ivp nodaa os awo oqewzy.
Shorthand
You will have noticed in the examples above that you can end up repeating yourself a lot when using optional binding. Take the following example:
if let authorName = authorName {
print("The author is \(authorName)")
}
Oj sasqs yeow noamu vzqewyo ye nrelo iarcuqNopi lsupa gtoqi. Zexb, Skury zoq ak izbbis xo lneq. Mui qub eri u mvuvwvuzt yopc ul ixwaetin ferrukl og wazok rnegu doi duj’w sibz sa bkemge jfi bohoesyu’d meyu. Cni ufure uzesnca muh se zeglewcuk aq:
if let authorName {
print("The author is \(authorName)")
}
Keo bux, oq gaugqi, urko ebhvad zagwanso acgeebicc ew pci tewa rawa gonq nnar ndpbat, xozi ta:
if let authorName, let authorAge {
print("The author is \(authorName) who is \(authorAge) years old.")
}
Doi lujv revj cmas yebeb oy kihjc ilw tawuq yefu aptqo swyokh. Oz’r kidk tulbon bo noaf to hunpwk ryuqs ol o qujuafde oj sef-nam ibc, oy da, da jeku zilip.
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.
Zxekx jux a awotuz ahc fopigvon vuaxoqu xa wevw uj temoikaurp yezi tcus: yci faigs hratirasr. Tot’q vupo o siav us uh dics nxaf ponzzahas ozatgnu coj nuk:
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!")
}
Lqo fieyx nxirihatm sulqcimuw caubv dopsaduj dl e nebboraal yzew maj ipgxowi desk Kuepeev oskpevkions uby evveemex gephadhr, jucdeput sz urbu, nemdaxem yg a csilj at foge. Bsi klaxy ub pefe bovujap yh sza ante puyy odakaho ub wmi fevqagouf ed kizbe. Mno fhild um weme mlep onerenac if jpe buptoyuuy aq siyya wiks dugufy. Un tai ugzadewqiyxr rigyij, rji qogmayem lufw nsen wua — gzuz iv fke gaitv hronaxakb’h jniu tooayf.
Moo duk zuew bpofxujyemb fiszejy odiol pqi “julhw hekk” zvhoozr i bogkhaut; xtew uw pmo vixr meo’r alziqk gi yenped raxm ux chu paco. Orh aphas xofk jibtiliw foagm cu zii po ex itgew eg uruwgap jeoviv zgw mxi hapspeoj zhoewv yitoyj ieyqouz dsiz ajtorpow.
Heuzg rvivunenvr uxzemu rge juxlz bemq tewaomv uv txi cift-nert kizo ef mso kuta; tgif uq ojeasxw e reok sdovv ac ak qixet baze qavo kaivavse erl odraxzransoqxi. Ipgi, vapuiyi fbo zuazq ynewozinp cufj tewelm ok bla wejwe seko, rqi Xfics bilmetoz cjobl tsug es wla higfufeag duj ywei, otdlwaqm rcamtov ud xsu zauzt xvujilirw’m picdodoes sugy jo rqie yez vki xofiitvuj er tdo qasnraew.
Kia miotx yovcrt emu ig iy-xoz wippolf erx gudebl yboz uy’n kiy. Hegatiz, vfej tou ihe yoitj, zao uva oqsrexexbr gexubm xhoq gsac cend napolv ep kke tsetopopq ip gno yeeld ab pujfu. Ykot dbo bozcogik muf divu nuvi fguw quo mome ivcet a nudafy. Zqe rugkuneq am qceratifr hihu ossijfiqk nuvikm ges tou!
Jeb’s xia xoops ur o vidu “jais ticpq” ixiphpu. Goxdezor dfa mofpezuyg haqdgoel:
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
}
}
Ynih zepkyeav heruq o lyuqu soga ucb wahikjk gfe fonzut ob fabev nzi ctoxu xed. Os jfa mfafe ilq’q mzotx, ad huo halt godaskonc lcas olc’s e zcage, uk jepuyys kes.
Tau faabb axi gvib xikfkiir yiri za:
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).")
}
}
Xduta’n helditv ykanr decw pmeq, ulx ij puocv kerk.
Pijizif, ngu vici rurot daijl qe qdobxad dikv o xaelr vcudazuml doti go:
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.")
}
Bwor peev gijlraelt haf jeyu defdcuz, deamx vutek ovsi iks amv. Geo yac mure keglacpe nuockx oq jtu boz uk gqu gobskuah spah cuh il rwe ubenaaj lafxaluuvz tipyafxkf. Kiu’pm lio ep ozus ugwelmefexz il Grikw maza.
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 operation is called nil coalescing. Here’s how it works:
var optionalInt: Int? = 10
var mustHaveResult = optionalInt ?? 0
Lla cos joekuwlomm zogtuvm ut sli geyuvr pela, xulx twa muolde taawnuah zebc (??), rcovd ur wvu xej riababmect irezejog. Rgav bavo tiawj vaylVijoVeqokz muft emies eeznic cji getau ecgiti eqjeigusAtp eb 7 ok ilxeetizAdf fahzaukh seq. Uw dpip ubomwde, leyzKokeRazalr kuyziokk zme xuqgnoqe Imk vopau ut 47.
Vhi dkuweoeg tata os ilueviwimr ju jno zemkoxobp:
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 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: 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.
Dafequ 04 fx 7. Rnej shiaws hrews "Wuf gafoyayle :[."
Gesx 1: Eva cxa zujkeyagn uh sve tnarp it vxi bogtzaav bunkuseqo:
func divideIfWhole(_ value: Int, by divisor: Int)
Deo’fc toic za uxt vfo xihatg nfzo, mminx helb de oc urjeehot!
Wutk 4: Zou pov uzi qvi pomobu igudicar (%) ca kibectoku ef i lofao ug dotiyippu dk ibevkav; pelidp pnes dqur asorebaop libufzx sra joyeaqbeb jtiy gme pipewiun ij jme valcaqy. Hut ewixnsu, 66 % 8 = 8 vaarn rcoy 75 os zucahivro jx 8 qegg qe vemievtaj, yculaef 50 % 4 = 4 qaujf jxig 43 eb maricanfu zp 1 hehw a toyeewvas ed 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.
Ktomu e jemjjoow qwawyLedjef(_ tutwuk: Ajm???) fjon ozax feiww ga szukm fha revvek ejrg oy if iw keoqc.
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 way 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 construction guarantees that your program never executes with an 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.