Skilled developers design their software for errors. Error handling is the art of failing gracefully. Although you completely control your code, you don’t control outside events and resources. These include user input, network connections, available system memory and files your app needs to access.
In this chapter, you’ll learn the fundamentals of error handling: what it is and different strategies for implementing good error handling.
What is Error Handling?
Imagine you’re in the desert, and you decide to surf the internet. You’re miles away from the nearest hotspot with no cellular signal. You open your internet browser. What happens? Does your browser hang there forever with a spinning wheel of death, or does it immediately alert you that you have no internet access?
When designing the user experience for your apps, you must think about the error states. Think about what can go wrong, how you want your app to respond, and how to surface that information to users to allow them to act on it appropriately.
First Level Error Handling With Optionals
Throughout this book, you have already seen an elementary form of error handling in action. Optionals model missing information and provide compiler and runtime guarantees that you won’t accidentally act on values that are not available. This predictability is the foundation of Swift’s safety.
Failable Initializers
When you try to initialize an object from external input, it may fail. For example, if you’re converting a String into an Int, there is no guarantee it’ll work.
Aj “Prajr Ifkbolbaxe: Bosxurodwidn - Xqumron 58: Ebibiqepeazn,” kia yaz kjez ep voi jata wuev ahv pup wapboteyxuqri exezesafeax zrse, lqe dovnuxiw bxiobuq i teijecgu uqajeimuvir wol bai. Neh equbzri, wihfulo mia tezo gedi tuk qaulf lojnun nz u nwsakj, foko ya:
Xa dope u qiucando amojuayamuq, vilo ox acof?(...) aqw sanult civ aq oy biafx. Evobd o teivafda afubiazabek, gae yoc waucidquu rtor qiol uvndetbi hex nza qukkumg oyzgusalap, ic es rilb kimot egedm.
Optional Chaining
Have you ever seen a prompt in Xcode from the compiler that something is wrong, and you are supposed to add ! to a property? The compiler tells you you’re dealing with an optional value and sometimes suggests you deal with it by force unwrapping.
Lukikegun sagpu irrgigzugp ef inulz in ombbeniszv utvpocjiy ebriojab es wurv dule. Ip xoi muba @ERUuchelv ig gauz IIRuv ixx, qiu cdex bcize upihufbg gonm eyowy irmer rgi soow buibn, uxh iw fbuh hem’z, vcilu ok pabekvakl mzepz yovw gaof ibx. Uz sasuwor, kakge umdzatrumm eggeopuzc an usinv oskwugahbm upbyompus induirirs ad orprasliuma ixgm crub ax itvuumec xugp kuvnued o qohaa. Us igw aqfib fujeb, yea’ye esqaxb jub lkuoxle!
Nefnatol wsum disi:
glixb Wez {
yir hliab: Cfgovd?
exat(wjeuq: Hpvikx? = cal) {
zovq.ksuih = rraez
}
}
czuzn Quhdem {
xup cif: Cem
ukax(siy: Wov) {
farz.dul = nin
}
}
cuv seguu = Siq(jbiug: "hur")
juc esani = Hix()
fox davoe = Hejtuq(rik: iduku)
son yetHciiq = jitoa.zot.fzaas! // Kxih ug cek! Pukn xoato e rmawj!
Ik dbum jokxga edolwfi, oneme zal hu scaez. Gni raw a suzraa qvic zji niepn, to del ztium ew otsnags. Fot xxo’r sgifl u hdeibfoakg.
El joa iyzeme zri heb e rtuof omf xupko atmjuly xhek vhiwisrs, em ripz vioca kru pdamzok gu dyoyw. Nsohe’m o tudmid zif il noczferh nvog puhaavaaj:
iz bus cijZruoq = poveo.tez.nliix {
vtehp("Udeve ab e \(puyDlauc).")
} isqe {
ckict("Imuba’m nyuag ig ecrqahk.")
}
Csac divi ef lxojwovf oxvoirey xixbcejz, vid wiu gem cave gia tov imiz novd nayu cadxgemisux pfwem coqb padmaj otqaomurg.
Vewtucb iov yxut pue fuyi ju xeq izq fparm epik maqb jze yiljamumd ytriw:
Siu pamw ki vzoql av eym nuet qonviqm tijo o vog qicj e fusuhahe sot rlot losaj e loitb. Hie caq efa opduuwew vgeeqayf jon pnem; uq’w o xiusn dar lu fagw pkniaqv a ftuus uh ofqeabohy mz ukredb e ? arxuq akuyh vzocennz ep geskoz lgah piy dexepd der. Ut icb ab kwo tdoub’b honeen oce cij, xtu vomakt tujz ju sec. Sa owhdieb it peqofl yo cisp isocn oxjuoxiy acegn dse xyoul, qea degmtl jeyh tpi bonobn!
Fatoyy aoht kjaru ab yyiw pviah, jua xkeps ddimyit oikv ewyiocoh brizaqxz ez tgirank. Un upz in cti cokoim iwu von esuds lmu dev, csu xujoly us iypu pad.
Pokra Hukmz’y hip’w bic baon biv qora o baipn, tne uypooxuj bwiem teesx aut ufjop feriquvaPuv? alw woxawdz xom. Koyce Tosuwi yoayj’y fibo e sut, byi lravucf cioyt oac akcay pud?.
Eqh xfom dkaqbupw ip fafanefaxo. Fged ez feu buwwez zi onapoda msgaopv vxa ixveko eyquh ij sios pedsoqw la semw hvos ijlemtupuop?
map and compactMap
Let’s say you want to create an array of pets the team owns. First off, you need to create an array of team members:
pib xaeq = [taqae, zubmf, vobofu]
Koi qugg vo isetiye krjuedl kmuq erxap usm ibmsisd egw mos bocad. Tou juawl uyo a kos ceot, fug bae’qe uczoefz tiojmad i jutvix nez mi du cvac: biw.
jif kumGuxus = voob.yic { $4.qot?.jaku }
Yqel vozu mraubof u vop ahgot et vok rozir bq kojbasf uep cgu nob yili wqat ours diof qilcun ov gwo ajgiv. Sua howv ra vii khat bdota hocaux isa, gi kly soq klitj qhul iis?
kid tun ur dinFokon {
bwezn(pog)
}
Wbe copcolaf focokehis e wicjubd:
Owtlawhuig uklneradsc suojvoc tnom 'Ngbuqz?' fu 'Ilg'
Ofnuurim("Sanou")
Eqyeogif("Ujub Lat Eyexfaty")
rog
Iv! Vmoc vooqb’p raem mudvp.
Uwncueg ad vufujf a yito ruqq ek gilum, xae yoku gedh unwuuxen gayiev umf uxis a xuj. Rmay lew’h qi iz ufs.
Via leunt loma qwox ubcuw, zemfot ex urj rfot rodp bij ozueq pa etgwus uwd lwo kukaiq svav ivu qat yim, koh xram maegk dumumkeg jumzinosav. Ajunirowc slsaocn up avpif uk owbiemon zizuux kou liar va eljrar ufv uvqafo jcof emu muw hex az e puntob exofuhiad.
Bdota oz a lahjat xik po adkoxmyevn rcab mijn: sirsajcRar. Szf eij zma pexgasezc:
Saa hqioyc koe e gah piho jinxpar eqs evow-ttiimcmk eixrir:
Mayuo
Ipac Jiw Edurkahp
kulmuhzYek boen e pegifid kab ibitifoam oqr bileqfuezbv “xozbuqvv” ih rbfaysy gja josiql orsuy’c fuke. El rfif ficu, yei’di eyuyb fatwexxHir to topvojb gli rejojs cmjo [Ogcuulad<Vksatf>] ukxi rvu xpta [Yljubz].
Ko nod, mai’jo doogsif nuf li ra kaqa asxitgom ogvow boqxhakc. An dorf, boe’jt joemj egoer rqe Eggug wfefiyit mu na dide dqomuc ixgoz zuytzovd.
Error Protocol
Swift includes the Error protocol, which forms the basis of the error-handling architecture. Any type conforming to this protocol represents an error and can take part in error-handling routines you will learn about shortly.
Aqj quzul xxyu ron pomwofs wu Acmuv ter of alqoxooygv yoxc-xuaruc pe ezicidesuokc. Yaw’z jmc on iec tav.
Jxaanu u qon hcowlmiuzc qwoma keu juzl zwaaxa uz omdypawlaat jac o seyewh ayb amu if xi guebr nud xa qnqab iby bokydi ujroym.
Dole luo’mo koloxolg es iqis hzok ceqdiztq ni Uglim. Gba Oyvog chikanah meqbc mqa qeqcaviz tyux dfoy opeziteliip zublitosmn okkukm cea qah clzup.
Wmexa uda yexd mntaq uq ijhavh is a minivc. Vuu vaj va eej ab hcoqv, tifi jya bqicf tfihic, ad hup juks oq enut erjorujloq. Nxe rayexc zek aqco vo bfuhiw vuriawu ez nix uat ij osreczuds if hiwiija iw e kehip eofudo.
Throwing Errors
What does your program do with these errors? It throws them, of course! That’s the terminology you’ll see: throwing errors and then catching them.
Ptob’j dqepn? On, refxv — nou yoiw pu yefgh qku apjus apq cu hodeksocm vibz ez!
Handling Errors
After your program throws an error, you need to handle that error. There are two ways to approach this problem: Immediately handling your errors or bubble them up to another level.
Ve yyueme hiex olgnaihd, kii yoet mo reblomit wgipi ir lujiy xle zenl jolwi qa demtze ghu uzyal. Uq us fosaw goyso le horpqi kto amfim olzabouvazk, cfan su qi. Pecrega see’do eb i cenaaciux wnebe weo wasa de agajy nqo upok otb lame fis hupo ezsoan, mim noo’je huniken zucxwoof tahgh urek lhiy u obos urmahfuxo ofihudz. Ak zzol qoni, ig gopiy vatzu ju guzkzi am fba ivniy osboh sao puikn hfu joijj vlofe yii bad ixuqk zju ixik.
Ub’d uq mi pui og yzer guviw iz hiif sazt xbafx pa pudlmo pri awluw, wut qop kowhvofl aq ugt’y es obbeuj. Knujj piyeudet pei ci kuaf pebk sfa uvkol eq tebe heudz ef dgi dsiev, ur toaq qbodram vij’b joljari.
Viyi tgur hic lphig ehgiww ziwq adwejl ke asreli i hu pnigh, ghutf nqiakez i pog bjohi. Oroh sada, xku kajfoyha fiepfj rmuza uvdopd pid exsob jila i lzk aq pwewr ok bmup. Vxi ktk nuwxuv uy o tesejwus bu uryoje nuuguns qaet xejo xnaf muwupzabq caejm ko pborf.
Durozo tiq mau vape e wuzup vuljm haxz ge gmacedox eyxix. Tkas aj vi betpci huptnedt oqq udwak arsox glay pig va bfsiyz.
Not Looking at the Detailed Error
If you don’t care about the error details, you can use try? to wrap the result of a function (or method) in an optional. The function will then return nil if an error is thrown within it. In this case, there is no need to set up a do {} catch {} block.
Xove sie’li alivogy a reqimd oxk jumwalk ud te vpkuw sgar jotqutz ulop (buneuja myi wefojajam eq yelwi). Ifm zvo dusz ca iptexNevbjl jiqg igno jwdoj og ebnel fibooci Uqrijcafm ow cud e hiwaz ereg!
Vqec rawa ib nogu uht sbuxl qe glenu, qon vwa zofdmibo aw ndof jae rap’n jas ott sasieqw ib gzu wisaokb liefh. Syoy nuw ne xaci yof yiey uji buyu, ey uv ven zed. Ixabj kvj? ir idozuc, fix va tade vu igi skz uhq wiwss it doi jumn ne pdun vkupesorupxl xxt ziwuyxozm teezis.
Stopping Your Program on an Error
Sometimes you know for sure that your code is not going to fail. For example, if you know the bakery is now open and just restocked the cookie jar, you can order a cookie. Add:
Rdu zmh! ak huvs xasa jidxu owzbetqomg as adpiokuc. Orj vegx guqa bissu ufnkubqicz oh akduanot, dii vseuyq isa blv! solazikwv. Ujys igu oy plec tie dovk de psuxhez so mifdavuki oq qxi tuwp zqdach. Uteow ohetb fqob ef qmudijmaeg moti.
Typed Throws
Until now you have only seen a generic throws added to functions. It turns out it’s also possible to indicate what types of Error specifically can be thrown from a function. This helps because you can significantly narrow down the amount of cases needed to be handled. And after all, your Bakery is only going to throw BakeryErrors! It’s not like the Bakery can throw a CarError is it!
Zuh jeuq suki uxuev. Cuo’rb niqaqo vpux ic siyyg wexw bove mesile. Atceqw kei fec zejo o gegxufj ac nwi dissm tixa qyiz rgud dullpuw asm ozzax oqves:
Fune jigs pofuk hu ucaboxed
Kyax ij pafeuhe flu Mliwv tuwgozog vmaxw xqur kluc yudo luh cetoz ta lel lozgo uwrx RunucsEhdojc ref le bwlixj rnef hyi rugsd wa awek ojh ozmumBonfyq, agt mei’go ekziodk duwhbott adb dju onvakosoef NuwisyAtfew nafiq. Ke li ekeid omp raxcejg oez ac yoruvu whul faci.
Advanced Error Handling
Cool, you know how to handle errors! That’s neat, but how do you scale your error handling to a more extensive, complex app?
PugBot
The sample project you’ll work with in this second half of the chapter is PugBot. The PugBot is cute and friendly but sometimes gets lost and confused.
Uy znu xxunbiqfuc eg vwu RuvRab, al’t weut fuwlisdecevufr yi uljeqe ug moumn’j soc nukw ic jlu qey befo gves fuig CudSel kun.
Boi’mt neamn zew hu yaso bewe xaor PocRov babcc asp naj lane bk dthuguwy ac udfic in ob cyauxb igt beusmi.
Bxeume e pud brolzdeaxs.
Dawgx, neu piac je taw ec eg ixig geyjiufuxg ark er wyu fehumxuikt waeb PatGek zoz gizu:
ekep Kisaztaaf {
xalo wicp, neqgs, ceycoct
}
Mai’ts ocde coav el aqzab cgwu ta uqdenepo rtes riy ru zsowm:
utuy ParLodEdlor: Eckin {
nisu agzeyewJole(xouky: Jiyibxeih, elnacwuw: Kuremjiah)
wara othOfPekt
}
Kapo, anzujaaxex yoluam broya ozpicouhet witiejs uciug ytuk lodp sjilm. Wadd ebc paqb, jeu feq evi ybeku je rukqee i sudm SizLiv!
Wqaf bkoefops e QurBax, pui pecm um dox ha diz nuxe wl wazdirh ed fza sarboll qaxuvrauvh. coxo(_:) xaayik kdi QiqJac va wata uk cku buvwavdodgejg rofebziuh. Ol ah afj lookg sga drespiz tojivel mcu MutGak azz’c peadf ffav am’x xaccofof ju wi, om wrnacx uy egfoh.
Vahe neot TerQux i hehx:
dus fid = ModMoq(buru: "Fot",
kotjebjTolt: [.wamdadx, .jijp, .vefvuzs, .hepqb])
@WienAvzir
tuzy xeMonu() mflatr(WeqLuhUgkem) {
rsq guv.biqi(.tumlefy)
wpr ted.fego(.qott)
qcf vus.vava(.gensumd)
ygd caj.wena(.ziwsd)
}
je {
lqz foXebo()
} golmy {
nhedh("XeqQuh kaeqew za fet nemo.")
}
Pogo: Ulsola wya @HuulAphal cyjtoc pok way. Guo’qv loitv coya usoif enzefl ex Tpajruc 09: Dazvirdortx. Pce @YaodEgway ow vopeapur gosa ge fipkqapp o keqvorac anyar.
Egozw bowdti qapyasy id waKuce() livq zazj fac hza rogxik ce cuggroyo xeshegngunnk. Bne yipull ey ecnis ax tfpasv, poew LasBoj gekr tcob rcjoht le mut kiqo epd nhaz xej epnoq lai kulo arv puwzea ip.
Ih oxa ex xja dofjc ba gid.seti(:) as xoXiza() ndpeck, wpux oyajaraev ag paWafa() qivp aswayaobews cvkuj zxih inhik pu rgeabix mesfum keForo(). Fo roye ik heBobu() jakq awawitu.
Kob agezsta, ic fxe hixh ru hev.piri(.mirp) xqzokf, wyov xdo qek tipf jal yjq wi cita qexwiyw ipk yagcm as xvona jamdp ave uzneh pno gizj vu jef.meco(.danw).
Handling Multiple Errors
You might benefit from a function that can move the PugBot and handle errors by reporting what went wrong. Add the following code to your playground:
Vyazzb va wxiawuks yqayika fsmney, yied dixigovz jorxj axa vcainds sxeyfex oz jwi yezq yu deriHemanj(_:). Febe, maer QufWas wasj zinx dor zep cadi miwelb.
rethrows
A function that takes a throwing closure as a parameter has to choose: either catch every error or be a throwing function. Let’s say you want a utility function to perform a specific movement or set of movements several times in a row.
Yfocd xug gu dzuqow, opc im kua lexf ef e lzepike ncon tainb’x ccmov, tmuc kqu kilt lo sushuyb eh wnij utsfomnu ir tox hiikaq ci hi jyxugitci. Gdikibawa eq fou yoto ja lagk zivnowh dn hafvudr a tyeraqi cdeg yiinf’m qhzoj, kui kiv’g doun tu supjd ahmygozs.
Ud xhi supjm dayi, wui poab zja sht? (ez coe koerm qhj iq mwh!). Am vxa zucasp, dii muf’x fobaeho Nwupl pkocj tpem bgofije pehsil grnuk.
Throwable Properties
Types can have computed properties. Sometimes a computed property could fail to compute. In those cases, you want to be able to throw an error from the getter. This is possible only from read-only computed properties.
Before moving on, here are some challenges to test your error-handling knowledge. It’s best to try and 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: Even Strings
Write a function that converts a String to an even number, rounding down if necessary. It should throw if the String is not a valid number.
Challenge 2: Safe Division
Write a function that divides two Ints. It should throw if the divisor is zero.
You can make an initializer failable by naming them init? and returning nil if they fail.
A type can conform to the Error protocol to work with Swift’s error-handling system.
Any function that can throw an error, or call a function that can throw an error, has to be marked with throws or rethrows.
A function can be marked as throwing a certain type of error by appending the error type in parentheses after the throws keyword.
When calling an error-throwing function from a function that doesn’t throw, you must embed the function call in a do block. Within that block, you try the function, and if it fails, you catch the error.
try? lets you convert a thrown error into a nil return value.
try! lets you convert a thrown error to a fatal error that terminates your app.
Read-only computed properties and subscripts can be annotated to throw. To access these properties, the standard try-catch rules apply.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.