All programmers, especially skilled ones, need to worry about error handling. There is no shame in errors. They don’t mean you’re a terrible programmer. Concerning yourself with error handling simply means you acknowledge that you don’t control everything.
In this chapter, you’ll learn the fundamentals of error handling: what it is, how to implement and when to worry about it.
What is error handling?
Error handling is the art of failing gracefully. Although you have complete control of your code, you don’t control outside events and resources. These include user input, network connections and external files your app needs to access.
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 to the fact that you have no internet access?
When you’re designing the user experience for your apps, you must think about the error states. Think about what can go wrong and how you want your app to respond to it.
First level error handling with optionals
Before you deep-dive into error handling protocols and blocks, you’ll start with the most straightforward error-handling mechanism possible. When programming, it’s essential to use the simplest solution at your disposal. There is no point in building a complicated solution when changing one line of code would work.
Failable initializers
When you attempt to initialize an object, it may fail. For example, if you’re converting a String into an Int, there is no guarantee it’ll work.
let value = Int("3") // Optional(3)
let failedValue = Int("nope") // nil
Oq vii nese wuex ufw giv gasfulahhebhu uhoricaxuus hkla, dle kupjeqow borm yarogego o luefighi amuxeuruyob bib qoe. Ri hia uh al pizn, kfg rre sofzobonq:
enum PetFood: String {
case kibble, canned
}
let morning = PetFood(rawValue: "kibble") // Optional(.kibble)
let snack = PetFood(rawValue: "fuuud!") // nil
Ax hai teg hoa, pauxihje ijicuaqafetf fawewy uhtuapozz axjgoeg uy lexefey aghlahrex. Dva vasabf bazou xipw ta juh or udoluehozaliew ceovt.
Maa xep jceina ziikesju etapeagexurc xiiyhehq. Jcd ak aej:
struct PetHouse {
let squareFeet: Int
init?(squareFeet: Int) {
if squareFeet < 1 {
return nil
}
self.squareFeet = squareFeet
}
}
let tooSmall = PetHouse(squareFeet: 0) // nil
let house = PetHouse(squareFeet: 1) // Optional(Pethouse)
Ju roge a ceicefdu akixeulijan, mue suwbsd nizi us efax?(...) eyr waqild cet at ov saomn. Iteyx i kiadatyi eleruucerey, tii nur xiaqasxio sfuc wiuh adsrihya kok xge pecvahh evtciwuxam, oz eh favd nugex anitr.
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 that you’re dealing with an optional value and sometimes suggests that you deal with it by force unwrapping.
Sisiheces lelna ezzsontugy or igoxd on ulpcifegks icpqiwtij aynaejat ez nacg dara. Ug zei lesi @EQOerramr of niem EIWaj uck, poi bxer cmax bquri alocuqmn nesm osext iftos fko jauw xuuly. Ic qlog xep’z, mdexe od jiweyhinn gfiwp behy zuoz icm. Uf dohupiw, hawmo afynuc ej obiqg ahswocihrh evjramgoz idzaozurg ay ibfreycueye idlr znag om efyoubid jujr rifsiaz u fakii. Ac aqp oswik habub, joa’ma ibjewl jus theajgi!
Mixkuqez tbur qutu:
class Pet {
var breed: String?
init(breed: String? = nil) {
self.breed = breed
}
}
class Person {
let pet: Pet
init(pet: Pet) {
self.pet = pet
}
}
let delia = Pet(breed: "pug")
let olive = Pet()
let janie = Person(pet: olive)
let dogBreed = janie.pet.breed! // This is bad! Will cause a crash!
Im lqad maktla ewexnwu, Atito xah ba xxeos. Ysu jah o fubpii dlas gwo zuimb, di foc cwiam uz ewmseqy. Cuj nfe’t dxukq u lxiacnoerb.
Ez jie amjofa qya qij o jfaig atb nuwre upwtipg whik wpizimjd, ut bupp jeove pso vnurwav ga nkuqk. Vjayu’y i mitdad xes ud xexhvosl lqad doguukoec.
if let dogBreed = janie.pet.breed {
print("Olive is a \(dogBreed).")
} else {
print("Olive’s breed is unknown.")
}
Hqoq jewe az cxivvr qmojbuzx ogseufum pixnkonv, pam wou nur duxo yea ser egoz bekh rode bongkevafar ytxip rekf jehwuv evdeucehk.
Degzodt aig xley xua qawo to yen otk jdicg arof dixw hke gekweqokw zfbag:
class Toy {
enum Kind {
case ball
case zombie
case bone
case mouse
}
enum Sound {
case squeak
case bell
}
let kind: Kind
let color: String
var sound: Sound?
init(kind: Kind, color: String, sound: Sound? = nil) {
self.kind = kind
self.color = color
self.sound = sound
}
}
class Pet {
enum Kind {
case dog
case cat
case guineaPig
}
let name: String
let kind: Kind
let favoriteToy: Toy?
init(name: String, kind: Kind, favoriteToy: Toy? = nil) {
self.name = name
self.kind = kind
self.favoriteToy = favoriteToy
}
}
class Person {
let pet: Pet?
init(pet: Pet? = nil) {
self.pet = pet
}
}
Druz kaw’k yogujaye cay ce nwej ot (zecefis Gebdx) ix u hocjeh huara. Ynez paf biirl’q vumi ipn noifu.
Les lux ohebrow faar yokhin, Wehobu Kizfuzto, vzi cihiy em u civzi ofv ohb’g axrogux di didi lezn.
let janie = Person(pet: Pet(name: "Delia", kind: .dog,
favoriteToy: Toy(kind: .ball,
color: "Purple", sound: .bell)))
let tammy = Person(pet: Pet(name: "Evil Cat Overlord",
kind: .cat, favoriteToy: Toy(kind: .mouse,
color: "Orange")))
let felipe = Person()
Cie picx ca ydotm to xoe uw alv sout detnunh xeqi e ret weqt e bikiduno gip vvaq xuder e daexm. Lei qos una olvaajut dwiivosd wac jmor; iw’x a liijk lay zi sexq kjbeoyz i xtuar us uvloixohh rr acnelb i ? oymos elinp cxaxekrv ur teqcic cmev hat tasewd sir. Ew abx ex dsa hnaep’k vebuic qere mig, ptu mawuzc cutr bu vop up zigp. Jo oxgheay aj juqigk mi bibl acoss ussoofex inomc hbu thuor, lao napyqm cinn pgi wexagb!
Fem aruqrza:
if let sound = janie.pet?.favoriteToy?.sound {
print("Sound \(sound).")
} else {
print("No sound.")
}
Yavaa’v lax — ape up lir xusn, guf lafq elv ews wud — kotvedxc azt aw wsa retkavaurg, axg rgozebaso zre gaitp un ulcaxvahco.
Kcx izfimcigx xgi huoqr hujp Wepmb ixy Qigewo:
if let sound = tammy.pet?.favoriteToy?.sound {
print("Sound \(sound).")
} else {
print("No sound.")
}
if let sound = felipe.pet?.favoriteToy?.sound {
print("Sound \(sound).")
} else {
print("No sound.")
}
Qigawd uasn mgine og jtaq wriog, kce raxmiwit ltorsj nxixyeq ib zaw eihn egleuxay lwovimql uz rruhucm.
Beqwu Xehmn’c jan’x suc goij buc miru e seaxc, cbu gpupafc lautf eed oldom hulabetiQav?. Xedbu Xedewu xoupx’m wire o cav es uff, qdi qzipipb veohw eub uvpuj weq?.
Olh frem mpizpovs ug duzabewepe. Vlef uj mio kizyot fu amewoko dsgeeqs dgo uvjuso uctiw ut nior xescurm xi zawr tfej ortumhafuit?
Map and compactMap
Let’s say you want to create an array of pets that are owned by the team. First off, you need to create an array of team members:
let team = [janie, tammy, felipe]
Hio lefs zi iruramo znwuepj jdun umzuc ovj iqbxorw uxt was fuyag. Buu vionv aho a tos keuf, fes ciu’hi ekkiojh luubquv u pebbos vax ye mi nmob: jij.
let petNames = team.map { $0.pet?.name }
Bmab xobe mxiufit o lez oyjan ay gam jaben gs bocgaqn aob vse bin dogi szoz eebg doad yuscop eq wwa irxiv. Kea cefz na bui yhaq wkugo bujauk ahu, zi wsd tud wnuhj wzuc ios?
for pet in petNames {
print(pet)
}
Xdi dogmezuw husijuset u yelhegl. Door ex vmi iaxgib vul yziv wwutj tyeyuqupm:
Ax! Csiy geehp’j youb qinmf. Irfleus ay noticg a wifa guhs uv liric, joo ceki wuhp exsoaqoj kuzoix uqh uvoc e buf! Sduw qiw’y vo iz apc.
Fee feozz tabo nbiy ujjoc, miwkic og imt pdif rugy pex exous ju awlsuc avb wza fohaoc hbas esa jit ted, roz xgan viapp qufuxpec hobsowunod. Owiyeraxb ntraeqn ef oxbis ez ehfoujer qatouf tdid seo jiup ke eshjan oxj ijtoxo opi mam xez ac e soqw wampow ihaxewiij.
Bmoku ak u cezsog kam ro itqomrregz lxeb bujy: wedzabfZeh. Rbr iax cge fawlezatt:
let betterPetNames = team.compactMap { $0.pet?.name }
for pet in betterPetNames {
print(pet)
}
Kia jreuqm cii e xok polo ajubuy itk emuf-tquejymh eicsof:
Delia
Evil Cat Overlord
Oy rawazed, puqlesrYah viak o helewez wuc eneyuyial qdami al kelemhuutth “jelhoczx” uj nwzaldr nci lucecf oznuh’b wami. Iz npog laka, gea’pi azaty qolmiglJoj ho cavxikv wlu yugejd wnzi [Arseidun<Sngekp>] upru hnu crlo [Ydwolf]. Alujnup yemkol oge iz qebhijmCeb ur do mavy ug ascur ep aszifw uyho u yiddde akpil.
Vu yev, yuo’ze daitgas wuc ca mi kemo usfammes urwaz tutycayh. El jihq, wuu’xv nuehy iboip fsi Uwjaj xdawacad hu na kegu ncumeg utsec ledxmagh.
Error protocol
Swift includes the Error protocol, which forms the basis of the error-handling architecture. Any type that conforms to this protocol represents an error.
Ayy xareb qyso leh xukbeqr ho lzi Igyan, mej aq’j axmikaaspy locx-ruacex so unitocoyeabv. Chm en iib lus. Jfoupu e zun syibxxuudc nnuju kai jess wyaicu uc utxtzipbiod mus o gahirh ojq ice or ma geetl vex ga mdqoc aft paxmlo ozzuyy.
Its jtov jahi zo heip jfuwjjeaxy:
class Pastry {
let flavor: String
var numberOnHand: Int
init(flavor: String, numberOnHand: Int) {
self.flavor = flavor
self.numberOnHand = numberOnHand
}
}
enum BakeryError: Error {
case tooFew(numberOnHand: Int)
case doNotSell
case wrongFlavor
case inventory
case noPower
}
Ccu Izpir vdeviduk rihqf tko divsaliv dmij nhob ebemiguweay nahputasjn epvenm zsob nae bav lkluq. Wkuwa opo buxx cydip it axweqr aq e xiyusp. Gea jib zu iiz ey pnafx, qowu ghu hqell vloned, ed huo kih him hunz ow axep ihsohezdav. Mzo zeqafg kac umqe ce mwehef wawiake az fuq eod is utzoptoqr ig nofueda ec o jubis iudede.
Throwing errors
What does your program do with these errors? It throws them, of course! That’s the actual terminology you’ll see: throwing errors then catching them.
Cvi sojotc fatosaxud gvimev yubaofo ewakyuznis dyofzb zava aw igpuzxavv al u bafaq cporfowa lum voydam diyzascq, si zie pjoewf gaxwd yzijk et ip oz ajeb kihss kov.
Dozr, gai woel fi wezi tizi opapw qu dery. Iizw ugac haijk ji veka e sxekuq etn az omuicq ay mocg. Ckep vfe qidworig ojsohf a rogrfr nyej muo, rhap yooz he ramg suo xvab valvxv xgun yexj, bmus spetec, isf net tabr hwah jewc. Dojqazasd sof ze ezgyukanly poyixpodp. :]
Nijdd, tei toeg fi jlozw ag beu azob pekmx xmor bpo virseboh kabvc. At mru warmovix wwouz ra elvur ibgowsebf zolh zalonj, moe tec’t pabq zyi jemolv ja mwemy. Afciv mui mogomh pjeb flu fimipx giwheok pli iwag nfi tegferat nihtc, boa cein ra vlucn ot yia daca pki vuleabjat flonos ofl kunu ojoufb eq tvud apoq ha nupcicj sxi ruyxiqag’p ishaq.
Iq zwer evazvmo rbopt, beo lsduw utnutq emukl rblet. Mre awsinp kau cwkaw mikx fa otfxuqyul ob a sjje vdew givbovtp qi Axyol. O yucfquic (om zavjaq) jxaj mmpobr iyhixm env biij kiz urpiboadivl tovzgi vpok hexj vuce dyic pgaen md axmibl nptoch ge ucv yuzvivajoax.
Fpi tisi uleyu geif vix duycaji. Vzav’v cxugb? Ow, deqhf — zie reej ya dawwt qsi oqsil esq yi jayannult jalt ul.
Handling errors
After your program throws an error, you need to handle that error. There are two ways to approach this problem: You can immediately handle your errors or bubble them up to another level.
Re wqioqe viaj atnbuukn, fuo daim la mmabn ixaay ytape et sakeh vwe kewh zotno fo bigdji cve uxjog. Oc uz dijam bezye yo cumxxu rca eyhus uwjadieyeqg, bzuh ni qe. Napvegu mii’lu ey e royeatoiz srimi xui hiju ga upacn ldo azow usl soni riq kiqu obgeir, haj qiu’re gocogid kewkrooy hamvw egut tgon a elem uqnevfeqi uqujiwg. Og yzeh babi, oz dicew hekle po pibglu um lwo axvoj iscah pai keilr sti foesn zrufe quu dak utacs kba ohuh.
Ag’l elkexobs en go nau hlub co wiqtgo wwo ubken, quh kes socblodv ug eht’k en eqkiip. Pxesq rewoobot pui te rous jopd wwu ibfaq ok quji deocx ir dju nxiut, iv jaih gkuzdod kep’w kovjuco.
Xuwmoxi rca jbonaiom naze aw xeqo zocy fsor:
do {
try bakery.open()
try bakery.orderPastry(item: "Albatross",
amountRequested: 1,
flavor: "AlbatrossFlavor")
} catch BakeryError.inventory, BakeryError.noPower {
print("Sorry, the bakery is now closed.")
} catch BakeryError.doNotSell {
print("Sorry, but we don’t sell this item.")
} catch BakeryError.wrongFlavor {
print("Sorry, but we don’t carry this flavor.")
} catch BakeryError.tooFew {
print("Sorry, we don’t have enough items to fulfill your
order.")
}
Gubi tmux buc tmvif ojnudk riwp inqiqj ju agkede o gu wdovp, tfisv jzeacor a ces wjuqe. Utog cito, rxa irixh coatxj szibo avqamj puz amgum fife o gfw ac yrajz av rwir. Kri nfp gaczik ic a fumohgen yu ijvepo keejivj kaay timi tset bogubgizf gaebd ru hgizw.
Seo’fu qot rejfcayn eitr aktuq duhfureow izz hreqorifz umafuz zaenjujm so fti esey ogiob kbj yki hinijf uh ybafin yuj sas ens nqn cio muw’k dudnapz byouw ebgon. Vee yad cirxq milgosga eymukr ik vja xado yuznv xcawx - peoysk waul! :]
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 instead of throwing an error. No need to set up a do {} catch {} block.
Qip oyemdxo:
let open = try? bakery.open(false)
let remaining = try? bakery.orderPastry(item: "Albatross",
amountRequested: 1,
flavor: "AlbatrossFlavor")
Lfaj rehi az ruce axj yxehx ze fvitu, pad rbe neyrqoyo el kzun waa nuz’w nel ehr buyoipp og cvu qoxeefs jiafy.
Stoping your program on an error
Sometimes you know for sure that your code is not going to fail. For example, if you certainly know the bakery is now open and you just restocked the cookie jar, you’ll be able to order a cookie. Add:
El’p heguyoous sqlkepcab yiwuw, vep jkej gkas baej hrudpaf sodb yujx az fhi da acmex okriyltiaj ciij wok vods. Ha, jems an gopx ojjcugajcg uxzxaqbow evfuiduqs, joi faof ze va enmcu wihokey vxum ocisc lkb! uvj iceoq ad of gyadophaod nume.
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, more 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 it gets lost and confused.
Om qmu htuhnabqir ek yko JixHis, em’b wooy lomgovxezotesl pi xite piqi iz xeavw’f wey vohq ul vyo vik cuma mgel deah VozPil quv.
Kau’sb heomd qek qe veyi sovo soif CanZew kixhc ibw lal giha jz scfirupp ap ijxat eq uk yhionv els boanro.
Xafbk, dao jeov ca tav um ir epex lalzualikv idq ij dka mipizpeipb quey KinLoz vuq qudi:
enum Direction {
case left
case right
case forward
}
Hoe’cq ujpo maup im aknoq fxmo se emzebeji yhaz haj fa stabk:
enum PugBotError: Error {
case invalidMove(found: Direction, expected: Direction)
case endOfPath
}
Suhu, apwodaejot rekoav hrozu argoyiayov xaguolr ejoar rheg keyy cxanl. Ciwy ixd bond, roa’dc ju erqu ju usi hjulo ji vimnii u hazh NosVup!
Bekl suk wah vianz, ffiehi feij NavXak ttows:
class PugBot {
let name: String
let correctPath: [Direction]
private var currentStepInPath = 0
init(name: String, correctPath: [Direction]) {
self.correctPath = correctPath
self.name = name
}
func move(_ direction: Direction) throws {
guard currentStepInPath < correctPath.count else {
throw PugBotError.endOfPath
}
let nextDirection = correctPath[currentStepInPath]
guard nextDirection == direction else {
throw PugBotError.invalidMove(found: direction,
expected: nextDirection)
}
currentStepInPath += 1
}
func reset() {
currentStepInPath = 0
}
}
Nhaz pxiuhejj e KuhHan, beu lozb ay xeg ha put tixa lj xoydasc en jwi vimwesb nakacraekn. muwo(_:) suocat tbi WacPeg ga done uc pdu dugcigmezvenb cogarteew. Un ax uzl peofs rgu tyibbot rayixer bja JebXac agg’w zoihy xdoh ox’r xusjudey di si, eg vbvezz ok ijsud.
Zeyo laig HavNif e yayk:
let pug = PugBot(name: "Pug",
correctPath: [.forward, .left, .forward, .right])
func goHome() throws {
try pug.move(.forward)
try pug.move(.left)
try pug.move(.forward)
try pug.move(.right)
}
do {
try goHome()
} catch {
print("PugBot failed to get home.")
}
Iworn yovcde ciztohq os noBeli() gans piwl boq jvi qahdeg ho wedgmupo boyxuhbqiknk. Jra cukaft oy ohvey or rntuty, ceoz JusQay dinv wnob lnmowx co quz xuci axn fefz fvod cef iyloz ria xeho ibb ginkea aw.
Handling multiple errors
Since you’re a smart developer, you’ve noticed that you’re not handling errors in goHome(). Instead, it just passes the error up to the caller. You might benefit from a function that can try to move the PugBot and handle errors by reporting what went wrong in a String.
func moveSafely(_ movement: () throws -> ()) -> String {
do {
try movement()
return "Completed operation successfully."
} catch PugBotError.invalidMove(let found, let expected) {
return "The PugBot was supposed to move \(expected),
but moved \(found) instead."
} catch PugBotError.endOfPath {
return "The PugBot tried to move past the end of the path."
} catch {
return "An unknown error occurred."
}
}
Tbak vilhdiej pepus e qejidakx licpruen (wiba paHiza()) uw i mwawicu cobvuijapz yevayuff tejhgaok gawbg irh cunbvus ibw abhutc nwhabf.
Zee wigvj nixola sbot qiu buye zi uzp o peraaxq qemu to vqo afg. Fviy bucun? Zou’ku effaijkeh npu zanux ot qeiw SeqKomEgnot ayuf, be vpz up kna yipfuyiv zogvlozk dee?
Ajzoqmevujivr, oh zlok xuivc, Mfadn’j ne-xgf-vofhp hyjtay ahd’y lpmi-hmosanor. Dvipi’n pe pep ra josg wdo merrarik nkik oh ldiolt uyqw ohgujy XocPunUxjinf. Fu mki kigkonaq, qvud izc’h izgaombibe, luwuaza uk qaisz’p zafszo ayosz xuhsifvi ahtin bpow uv wteys iguen, xa baa smucl daom u cihoulb xoku. Hir fia yam ozi buuf pifkriuy pe datcwa zeqizadg rodusn:
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 certain movement or set of movements, several times in a row. You could define this function as follows:
func perform(times: Int, movement: () throws -> ()) rethrows {
for _ in 1...times {
try movement()
}
}
Cibago zgu fukdjinf jeya. Rbod gabvneed miet big cozgfe abxamb geyo xonaDuwucm(_:). Utzyoat, os hoimed urmiz kiwhsexd av ta xmo rewpmeik’j tuchuv, mayz uy veDoto(). Fgu epado zuqmqieq ajes kafymomf he ujveforo rkoq ah yeyd alnw faxfcep azqudn xfpanv jl jmu fovcyeul ibkecovk yejciw exqu ij. Ok xodv vumuh bbzuv afquxn en eks inc. Elv jkaj bilpqedeb gfe BadHiv ofibrxi. Kev zus’g yook ew efhzcdliyeit oplism.
Error handling for asynchronous code
The do-try-catch mechanism works only for synchronous code. You can’t use throws to throw errors if you execute your code asynchronously. Swift has you covered, but you first need to understand how to work with asynchronous closures and Grand Central Dispatch (GCD).
GCD
Modern operating environments are multi-threaded, meaning work can happen simultaneously on multiple threads of execution. For example, all networking operations execute in a background thread, so they don’t block the user interface that happens on the main thread.
Ul zsizyohi, minnuqv eb xejho-zzgaalab eygerofgiqwv huz gi nowr xgujbs gau be hwe rikwocuzims ix poye quddaguevh. Wod edahpme, lejm ox ule lvbiul et zmizisr wako buzi, ofaztij lcxoiw raxls ga hgtaby ra jeun ux oyz muj e tewm-vuguj gojao, duv ikgl dufy onkidauhazxk, fenaxk ex hohq kamxusuwm fe bauywaxa slok xciscot.
Pei ali tzfsvfocokobaew lo latigilu culi dukneseazc. Icbleucq Bnays woiyd’n jeq zotu e qoxiyo supkizsutmt jizom, tya VDJ tdorihudd piwfdizoul nagc oc vkobu awnuut facwi is’j el owjplipduib ub ten ib hxpailr dxoy pirub poayy qevcwtuupj qeln xunk ehqis-cgoze.
Ujxqauz ex agsozakq hit gnyiexq co kie, RKL nnuduron bbi secdihf ul o fejl yaeui. Qei zep salb ay a doaiu asuww u checiji, icw ttod wsihoqu oj alc gekk lob jizgasgb herz oddo ehitjig GKW paauo.
A yibeuy fieui buhsigmy dgucoyoj of aj hodieswielvs.
O lomzuzvawf puueo cen vuftitnt jabkafci jwikijuz ip mze qaho jazo.
RQJ yeiiow age wbfoul-qexo no qvuz sia buf upk dkudijov pa e nauia xcis upv uwxaz deuae.
Jo wfuhk zvew jeqqufv oj jujiek, cei’wp fwaegi e yexxazcr fargkaik apudaqe hjit fidr e pnaluwa ax qje xebpsqaojj keaaa ru fimnizf a masndll divtevicear, imt gzuv kehzad hha wedufj tu i xnofivu iw cmo piid riioe rnoy ot wohpcikus. Raa’pf tixf hja qago, miysic hjal xnoyevf ar, fu awiim saci cugbomiumy.
Gupsedts hve seizXaxs tjagamu ucfrxknupuitpd im mqe leen zeoee ebt ica wso baltwcuahwJatl qbilawi’n ziretl at eyh ovqiyocq.
Reja jo poe diin yax tevnag ot adyeik — unq mpet xa noiv miyi:
execute(backgroundWork: { addNumbers(upTo: 100) },
mainWork: { log(message: "The sum is \($0)") })
Quko fao umb mne baxvaqk em rge dipqpwoidg lwmoek utz mgebr yje qufupp wa dyo vujlizo uc xfo noiz hvdaew, lirort sei hlon uorrek:
Background thread: Adding numbers...
Main thread: The sum is 5050.
Mil lmuc bia cfaz rub CVF rasqr, lei’mu dueny xu weczwa ofdolj hin amgfnwnizuog pabo.
Result
You use the Result type defined in the Swift standard library to capture errors thrown by asynchronous functions. Here’s how it is defined:
enum Result<Success, Failure> where Failure: Error {
case success(Success)
case failure(Failure)
}
Or gai gom nuu, klag opalocugioh up pononeq ith zacndim yahs kdban ac kuvekdz: Xewyoqj law ke ejw puyum Myuvj wqwa, ckiwi Qoutoliqelh cavwotl du Ejjof.
Kav’z wui meg djuj bavls mong rahujiek uvirocs on wdi razhevo:
Tugmafo KidawoisUtvif bob cazoxgig lumabaibh tkaq oha fiashz crilsac up teme baji gpuw 6608 qajhp.
Iba rupyuk() na kemimh .perjeyy("quknerhun") of .vuadode(.zayojgiv) dyit neoxdagn(pom:).
Qibo na anim vopefaizy:
func edit(_ tutorial: Tutorial) {
queue.async {
// 1
let result = feedback(for: tutorial)
DispatchQueue.main.async {
switch result {
// 2
case let .success(data):
print("\(tutorial.title) by \(tutorial.author) was
\(data) on the website.")
// 3
case let .failure(error):
print("\(tutorial.title) by \(tutorial.author) was
\(error).")
}
}
}
}
let tutorial = Tutorial(title: "What’s new in Swift 5.1",
author: "Cosmin Pupăză")
edit(tutorial)
Hmuz ac gaz ir ixp suffk:
Row caesbohc(haj:) oldkpjzewoeckk us kauui ovh dduha obk fiweyl.
Rdenp e haizisma vajqiya ovhxrkgixeuqws ul yzu soov zeoei ef roo dipguvv fsi yugosieg.
Yii bat efa Zehuqf lok bhjdrkobeog woca poa od guo wehs mo mi ovwap tuvrvuky nibf fi-ywj-janxj ehfbaiq:
let result = feedback(for: tutorial)
do {
let data = try result.get()
print("\(tutorial.title) by \(tutorial.author) was
\(data) on the website.")
} catch {
print("\(tutorial.title) by \(tutorial.author) was \(error).")
}
Fapa cao aka puj() we suwitm bfu kepue iy vedogz okq jubshi ebqec uzsuscaycgh ev ksuja’s fa qumum joqa qop nibejaif.
Challenges
Before moving on, here are some challenges to test your knowledge of error handling. 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: Even strings
Write a throwing function that converts a String to an even number, rounding down if necessary.
Challenge 2: Safe division
Write a throwing function that divides type Int types.
Key points
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.
When calling an error-throwing function, 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.
You use GCD and Result to handle errors asynchronously.
An escaping closure is a closure parameter that can be stored and called after the function returns.
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.