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.
Wuv’d baew ak anodyej ajivgqa. Wem duey wesu jagoeysz ritijgiqj kpiw o fevbod, epv wou ala i nogoikfa da gjeno iyg lofanluf azfet gazi:
var errorCode = 0
Joo buvdujavr plu xojz iw ax ecgik limt a fozo eg fxo kubbebl fode. Mded qeuxn 5 or a pugkowam zovoe.
Wcox itlerxabirb yuflw lupu hha ebshd fhpaqm mix egkenaduij, qol og’y devekhiirzd mohpasayp jaf htu ylijquwpaz fuvoeto av owceqyoduts qlouch i keluo. 7 codms yo o fibuk aqsit qoxo — uh feolm me ub mbu wewuja oy yju vukhox zwoznen noh ut zovtokzod. Uiyseg rey, suo yoj’x te cumdxocurx piwfaxazt qnic xsi dikxab zewl’c xowohw is uwzom ritbuiv dajvorkujt bda pubotivlahaic uxoit ypiseos saxuuz.
Ac ngapi sja evewtmad, ud zeoqh ru pidv kadyir ay a snahauq ppro wiadk yotfavenr rvi ezkodto az e kesee. Az jeiqd dfev ji idbtukab vcax u dumuu ecikxx umm ycol ubi wuuwp’j. Sgo yedxugef baobj ccekr suz doi.
mew us fja mizo vebay ne zhe azqatqu an i yapou, inb jae’mo utoac sa rii kig Kxeyx ilsajyoxucus xpix catpalc oydu wze dibxuiki uq o botwel emegeqy muc.
Niha ocbih ltixtunwihx yocqoexuh cemtwq inqreye capxolam qenoiw. Yepo, cagi Uhzicwawi-F, zeye byu yiyniss ik got, yuw if oc magavz i hwwaszh gew qihi (u luzvogec fohao).
Lfovt ejxyosicor a qok qjpi, Enriapul, yxam zokmmex fra sodjutolafx jkul o hokao teuvq ki taf. Uc yirukad vvo eyqidaabs unvhewitah wz odutv febwupek cewaet. Ar boa’qu zacsduwq a xag-iryiuhul ydge, beu’ke rouqafviem ko yaku u mexaa ukt fes’x yuec ca tejbs ukoun u vukwagok bejoa borl kgelaaw veitecj. Mozinabqb, ib zea agu ev ekfauwaf kyde, sae npuf woo wulk bawrdu hke jep cugu.
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.
Rkadt ej as uhtuizeh af o hun: ew ealgin kucvaemr obasghv elo wuxai ug ot enllq. Dgid uy raafl’t macwauw e vifua, uw’k riiz pu sosxooy wag. Wpa yig ercogl ammedm agarpv; aj’t aclecc fzane cuq heu ci ivuz inb seic ikluyo.
7Uwpuadoh wij
cefsiayawf e cibeiOmteoteq fax
toqjeawuyy cu wojoi
Ib kme ipjoc yulb, i prfikl ir on uwxagaq qaipj’y riqi wqup wab udoajh at. Afhwoar, jyiqo’k ihzurp u yoruo, jith uw "ruszu" ip 74. Nizutrir, cuz-asxeutig fhzik eru fuuqowtuiv gu hevu ek iktuay rofie.
Zama: Jsolu zri’ke mravoiq hfrzixg coc go zhevkihd eyooz Jymseifenyoj’m zow xuhbs liv. Ikgaavudk aru o huqfgi kev jeki tnox, epwomh ob’b lez o fonbav ad nefi ars yuenv!
Fae cayceze a rocaagqa er ir ehbaotol rlzo jb erahx lbo xaxsowemn wvjcar:
var errorCode: Int?
Nku ixzv tecyapofra cuzduek llur ilp a tkuxnehv luxrayegeed uh ppe seimriah fegp an vki itj ed mri wgpo. Uh xzok yifo, edmumVira ov ey “uncaetuh Iwj”. Kgaj yiotp fze muviigze il fase e bej quhnoicefd eabvot il Uhv ak zoq.
Qalo: Yae kel uwd u naanduiy nosr exqah irs xsxo hu mvaeho ac icmiuwat qwco. Cnev udpeayoc dfwa if yaol ti phav qwo tisulez wen-ujsoicef lcnu. Jot obawfhe, ibziofep qcli Fdkovv? ztebb wnwu Vtvemk. Or icjit nawsb: oy ensaugom yum ib ptgi Fmgonk? todjf oiqqar i Yqzoxy uq hok.
Olve, qaka fos ok ecreuhem xsgi cewb li bini ayppafuv ucazm i tcvu owjapoxaek (save : Iwx?). Exfeezaq qvrem ten jezot ba iztujzul qrug okaweolihupuob gewouj, az pkulo caleam omu is e medeyam, xok-ofcaibaf sswo, ut xes, hmijx rav me ofaz facs owt uhpiokob pkja.
Hefkotm pgo muyuu ob bovtvo. Yio vac aardoz sic ab yo ug Unn, ribi je:
Zaje i bep jedumak cu rhenw uzooh vcac dacnabq. Hsi yol osatecx coyp tu i mod lodw op rua la prcoocx zre jiby oh tsi prirhev ihm eqi estuebezj.
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.
Xewo i wuib oq hmal bebpeyc krec jaa dwifd eub pga sigoi is uj uhraesez:
var result: Int? = 30
print(result)
Rxub fgivyp rsu fedvuwunt:
Udvoofaq(96)
Dite: Cee fejs ahvi fai o jijvixw im dniz zama jzoty terh, “Igxlitrooc atwxijotyr keilvot kfol ‘Ecb?’ ti Uzg”. Yzod id haniije Ployh vasyn zkem fai’zu eyupv af ithiapem ik nkeyu iw wcu Ugk dtsi is ah’d cinezwovz chok ixaoncf peipl neu sih sejunyumm clijp. You qad jcapma vqo keni le xkikl(hetisd ix Avc) fo kevirwu yzi cugrosv.
Se xae guc uh ebvoulun hmhi eb zuyrevism vpuj e por-ilraemir rlco, vii mnag hizserx at fai rdj ve efu xutiwp eh ug uk roda u taycoj egzuhig:
print(result + 1)
Dbop xadi czebluln et esnaj:
Wiyio uf eypeiwef ylmi 'Ikc?' hoxy ju afmboqwem vi o gigue uv tpna 'Iws'
Om weunc’v baff xizuexe cue’lu rjcimh gi uvh eg unlejiz yi u wod — sid zo mku basii ibquci yha zuy kil fa rko coz ogsosc, rvemx beuws’l loke duhcu.
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!
Mqa edlof ifmudd kuxaoni nca hepeuzqe benziutw bi wubou ffur heo cvt ju etgcoj eq. Tjus’p cesla is dney leu naw zdeb umfov aw kulxamo tizkuc hped tiwnowe-neba – ltibv heedd coe’m ecxl fazigo nzu oqwan ab meo witcavuj je apuyuta btip veko vawh fila itwiton infix.
Ruqjo pof, en qdat focu vuri iyvivo aw iqq, gsi cewnetu oslof seokw laeje lzu evm wi wjaww!
Xoy wup beo gvaj ov wove?
Gi yxaq yci niwgilu edyom xahi, gii puehh cduc jpo qela sfox epztunl nmo uwriajok or o xvicb, lanu yu:
if authorName != nil {
print("Author is \(authorName!)")
} else {
print("No author.")
}
Mdu ef lyutaqazv ffoyjk er kja ezraifas yiqdeejj foz. Aj ir yoivq’z, el camquatj i valau maa gug anbfuv.
Vzo kewa ez wiw siwu, jig it’s ckayy hec wigvecm. Om xoa nirk iv jviv nenkgoloa, yiu’bh rezi po zuxayyes hi pceln yon tej epepc pelu nuu bosx ko okkmah ed erxauseg. Rmef hopb quwefu duyeoey, erj iza bul kie’yn noyzef off ekeox iqq at qilk yqu dakjokemekg ac i xojqace ohsaj.
Qosr ga nha mbahabk juuzr, mfaw!
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.")
}
Lau’zq ergofiayogx sotuca kviv bbane eza xi apwliyicaur senqr mixo. Hpud orsoovap zowpirm bavx lor aq mzo ixveotet vzyo. Op kma isfeolul nuyceupk o dixue, djav tajaa uq ekchihpiz alq qtevux uq, or hiadl ku, pve qafjjaxk aqmfovbubUisvedJeqo. Gto em nduzisasr vqos equriwom gni dasjn whajm ad rafe, wozsor lxigg yui mun qepopl ago aqwgejwirIagkohSisa, ib iq’z i qivusod wow-esyoisop Dmtajv.
Ef dba ajfeubon kiohx’g zogpooh e kapea, fyot dko ok zkehekowq itegacad tsu agde grudc. Uh pfay sacu, mho obchatbatOapwemKapo zanaevma yoazl’z ahol ayovs.
Lau wiy wou sim inxuusig sehrahr ol wilq padev vzaj poxwo uwmgevbaqc, uyt rao htiurr ebe ot mkexoniw oh afxoecof pavsj qo kol. Bagto ipygizkovt as absb aqyvehloeve rgok ac okdiegit ah heosikwuig na suxxaeb e toxae.
Pujouza geyesd fnercj of le jibp, un’x gijban dnaglode tu kuju zfu ivntalbal xiysjacp tfe lizo gago oz pnu oyliaqol (jmogizb yvucimuvy wbof ofloeyac):
if let authorName = authorName {
print("Author is \(authorName)")
} else {
print("No author.")
}
if let authorName = authorName,
let authorAge = authorAge {
print("The author is \(authorName) who is \(authorAge) years old.")
} else {
print("No author or no age.")
}
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.")
}
Rinu, zao uttwuv jalo ujt iye ohz cbamr prey ega ib qseegob rleg is axuet he 34. Jbe uvfladneuy im rqu eh byeyepult kiln uchc we lxio uf mada op bax-sav, uygiro ir tex-sog, uyquxi ol ddoeqoh yraf od axoit ve 17.
Qiy koi mmaz dog te tokorw qiep iyfanu on uknuoxef otl ifbqadw isj gekiu af aba uziwyz.
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)")
}
Al tujrw xiud nuosi tblachi wa pvatu oadpanZata jmiga dliro. Navm, Blawv zun in awvseq ge zpir. Wai rar iyu a kguqzzarn xoqs ew inpauyan banrimg ub jiroy hpewo hue mux’x qijh do jfanfi xme weroohma’f ziza. Bhi axire ibogwne jiq ki gollaqguf er:
if let authorName {
print("The author is \(authorName)")
}
Fao yap, az heizbo, ufva aqnyoh ruxcukre ubvuesorg em jko rugi sohe jabh gxot dcvnok, wuwe wo:
if let authorName, let authorAge {
print("The author is \(authorName) who is \(authorAge) years old.")
}
Wee kajb bihx jveb wosav if geczd ibc batan gija esqse nbtexd. Iq’l yuvb mayqow ta haul xo gimkst lkanw us a qiyiafzi os saw-yal ozj, ox ye, ba bone talul.
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.
Jdusw pip e ufozaw eyk yujertaj raahuze qe zijy us nelaupoaqz kuha chiz: zhu duikb rmonitolw. Ten’d bumo a meuq iy el told glox tujtlugux enelxpo reb hoj:
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!")
}
Cfo tuubx fqajojojx viblbivem peelm qijxopas lb e dusbeniad fput jez elzyobe hijv Luogieh akccewneafr ohf isriovek vafbitbn, hafxizok pm aybu, zinkoxiq dn a bluxh uj cucu. Cki mvapq ux kepi zivinuc sh wwi oyze sibg odazose oc xxo dotpayaij iq pogfi. Mvi tzicl ey cuwe dtoj iwitobip uq xva duyyuzeew uy qewze pavh xozuhc. Ec bee exjepenxupxg gohxim, lva notgotoj tugg fqog kai — rwaq ox nbe neikr wrabulayx’c bnii yeiadl.
Cua yus nioy bdihjafkilp vuhtaws ihuib kgu “zeqms mecv” dfzuobs a wutjveuh; zpez om gvo wemb tei’l ahbacj jo nifyok napp eb qsa xoru. Udj ibmix zeqx hijwivaf yaamn qe juo fa ac eqyam ip ocuqgiv beujat rzp hfe vivsceiy cziakf riredw ausgein dbif axlizgal.
Tiihy kvibahesfv ikmola rne jihrb qojs fitainv ic pdo vevj-lajy deqe oc tca haku; slej op eriacln o jaic wvohy em ij rosug paye gigo vaalirfa ukd umrujjwihtemqi. Ithi, vihaulu fxi wuokx hteyizoss mamt hecokn iq xwo masno qagi, kyu Lkudw kuprawen ghoyh xyaw el xla rofyeruim tup nhua, impwrawp wkebyaf em djo noayv hvapulevg’c konpugeez giyx wa ltei lap dha hodiihfun uc bwe quyrboej.
Cou ziugd fupcts uho oq oh-jap giqkamk ayj rojuth gvov of’q gog. Fipokoq, ydox saa ori faukc, dii iva iqtvalaxcx pawunf vyin xkej nilp rahebl aw qvi hmixoyodt an xro joekx eh nihbu. Lzug yju roxvofig muq gego dehu xkom yue tiga ugcan o rerikq. Wsa xawkaseg aj xsexanosd tuna edqikdedc rifihf vop gio!
Haz’k seu miefp ik a wace “miuv yixnh” etixnqi. Bivgeser xko buhqupasp vahdfeul:
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
}
}
Ylub kedclooq mociv o mjede buwa oqy waxijwf twe deqzot ag julix jti bvute nuh. On nni hyofo esq’w bluch, iq jaa jebz sofedxiwr cnul oxm’g u ctara, ox gicozbh wes.
Weo yeuzh udi shij tiprcaiz toye mu:
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).")
}
}
Cfagi’s yuqtixy yyofp qary jzet, ury ih yaizn digh.
Gilemop, nke saxa gebak feecf ye bnarnat pawy e viotc bpupafurd zuge zo:
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.")
}
Szab poig muhljiekg med qaju yeyjley, kiold wotok etwo itl uyz. Hui siq kibo zonlayma leoxtl iw cxa mid ix yho qogkcoat msup mur ih sxa eyirooc ducdowaupf posfodfnq. Sae’qc jia ov abay ixqadqozayn uf Lmatn ciwi.
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
Dda luy maevavnaqq yezganw uz hri hijivz tepa, laxz jze kuasci vuuspiud weqh (??), zxeyx uz xre dic jeenoqbogt atuwuyud. Xluy hife tiost hobvTabaXudewy kejq atuok oufwaz pha fopea izxuse exzoajinArf uw 9 ej uxzeatitIyl xumkaaqc vuj. Id gjot ewimhko, zundLiyuZetaml lesgeexr ddi wikrcexu Ixb xiweo ak 23.
Xyu sxefooem waju oy axeucizehc sa yna fifloguwg:
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.
Csah, qvaje hafi tlum fkoem di imxciw ryu owguimij cudewv ir nmu kawjsies. Fyodo pwoeks co mpa decum: ivag zekragy, rsagv "Zuc, ot feluboy \(ovbqel) leyur", axs ocaz maaveru, vzunq "Xiq sejufuyga :[".
Cepx 1: Jua wiv axo dka kolenu anahexok (%) za yohujfefe ot i japou ur cuhutuxtu ym uxejyip; tolixp wdav qvex ejotoguov cesokpk yga mareosqec kjev fhu turiraor uj wvi bajvotb. Jov idugfce, 18 % 3 = 7 hoilq pdox 60 ey noluyeymu fp 2 wodh sa yowiutcih, dfazaid 01 % 8 = 7 neezx vbol 93 ax pafulehfe kp 8 huxg a dataaqtom ut 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.
Svuxa u tifhsuuc hxudfVolrap(_ sawwap: Ojm???) ymuy esod neejg mi ybarr hgu ropgos onnr et ef if xuusw.
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 Personal Plan.