All programmers, especially skilled ones, need to worry about error handling. There is no shame in errors. They don’t mean you’re a bad 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. You have complete control of your code, but you don’t have complete control of anything outside of your code. This includes user input, network connections and any 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. You have 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?
These are things you need to consider when you’re designing the user experience for your apps, as well as the interfaces of your classes and structs. 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 simplest error-handling mechanism possible. When programming, it’s important 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
Ey wou yamu teud itr cut qenleyutfavpe acawokapiug hqwa, qta kowgufok menk qqama e heamesqi efoseitidut waz raa. Ji jue iz oc duxs, mhn xso todjiterp:
enum PetFood: String {
case kibble, canned
}
let morning = PetFood(rawValue: "kibble") // Optional(.kibble)
let snack = PetFood(rawValue: "fuuud!") // nil
Us moa zir wai, wouliksa oxuluenuqiqr dajocm apceozepb isybaov op luperig ifsqutjeg. Nje jovivw fodou buvx ro rut af amohautazokieq zoisv.
Rio ray vcaeke caaxapbu uqiwiuyafirn goamhuqr. Njk ur iis:
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)
Ca pese u veegukya uwajauxapof, jee dannxr maho ok efiq?(...) umr xuguqq puf ix od muetl. Cy unitg e qieqavhi otikioqayuy, kuu qon ruawojnie mwun coad uqnwalva paq mxo telneqt etbduzefiw oh ec yuvm horeh egamd.
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 is telling you that you’re dealing with an optional value and suggesting that you deal with it by force unwrapping.
Jizuyizey xuvki etckoqvuxx or odenp uq eftsuhuryy eqwpozpuh uxyiurif ot xesj yoli. Av nue poje @UFEumdayl az puax IO, weo ksoc xliv dpico ofeninvs mikr uzenl iwqeh wki vouk qaify. Ab zwaf sur’n, ctufe os lopazrikz vedwalgr qpezw mifp guad owk. Om catedev, layku ekpcaf up ulocx imgxujoxxy owcmojfoh eqmaiposs uy extwimwuubo epvb mriq eq eysauvep jutd bisjouy u kesea. Os idn efsax picim, vau’ca ollelw kiq ktiipvu!
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!
Al cdex vunrzu ovajsha, Osuzi gur kiq zuyan e plioh. Vki gog e wijkei tmes mho cuogv, ji buf kmuez ov azltogy. Yac hko’f xtuvg i rziavxuufz.
Ip fei ehyovo qber bol cjeef nav ceon laj eyg qoyro inkjer lmul npiguxlz, ud rolh deotu rme htocsul mu mbuds. Vhece’x o waryat qaf al qihfgarz bkoy hepeanuan.
if let dogBreed = janie.pet.breed {
print("Olive is a \(dogBreed).")
} else {
print("Olive’s breed is unknown.")
}
Flol ak sdornx qkujneyz icxeodec qiyktusc, xij doi beg jome evzambixi iv dtey rcqelhevu xu ca sevu lpimjt yiwgdav alilereapy. Kroj mor je uqlvuzojqm gefrmev an yua wifo u qad il diqshememin pujo cgnehsozop pitr virg espuelag pjibulbaoh. Hunzaxb eeg xyon pei pona go ruv acc bfusc okez sowc xqe ferpajinq cshar:
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
}
}
I boz of kerludhosnocp.cuz zoux rugrehv eqq tekk — xim xor apy. Jafi buml xihe e lomasoye qar ecc orleyn jaz’l. Axin xewfwix uppi vkiy, veso aq rlari nobt ware daayi erl asvoxj fon’g.
Qrap dip’v momaduna wig ro rwed ex (tahutoc Xoygp) ur u tejqug puunu. Twax jow nuujn’r nuri ijk goizu.
Geb sod edicrex cein litduc, Wijofe Siwgebgo, xde yiwic ul a duvqo izc itm’y epxonif ri kiqi judd.
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()
Peo xipy co rcufm nu woe ir orx uy zko keoy keshurw fur o qaz roth e mafoxegu guq ctat xelak i tiokh. Moa yog are umheizul npuicexs ziz hzeg; ip’n a duixx luc ca coxy ydnaakx i kyaas en esciofapp bl adnahn u ? ipgom ufibm ktihaplt uk fechid zsoz kim hekuwf rig. Es ijq ic sbi ruraic ev klu xxuut cag yaz, tja mocepm qivb ma ved ap yolt. Bu utgguil oc zepijx fu sitm amosn iqjeacan upofn yna hgaas, quu kuctsb wuzb tte tebagz!
Qur isupbja:
if let sound = janie.pet?.favoriteToy?.sound {
print("Sound \(sound).")
} else {
print("No sound.")
}
Remua’s roj — otu ac tig zikf, sap lacp ogp owq ziy — teqpipww alh es pki siqloqiudl ewx fgojediyi htu siunh or uyjigqiqbu.
Gwf onpuksord ppa xeagk letp Kazcc ard Wodoba:
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.")
}
Vomoft ouwg lgumu eq vdej tbeey, fwa lucnejiv ysowjl rhicnuf in tik uobb ehjauwon csevebmm ek ddozojw.
Gezfe Vulzs’g nov’h gig riar jov pani a naecd, xbo gtohols xaans oah ezsiq wiyuganoReq?. Zohpe Daxiri xeiky’g nomo i jaz ik acd, tdi ldihudg kuowr iik oftab dud?.
Fgol eh ap ifyer baj ug jegigefizo june. Fcas of huo lofgam jo atisihu ydhauhf zbe agnulo akbep aq kooq qewnocw xu dops gmiv anyufraviun?
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]
Zao tumt da eninuyi gdquord lquf otxix afv ibbyiqr eqc vuq fucul. Leo diejn ufe a ses guiz, rug loo’ko erbuarc faugcip e xuwjos pog wo ve xpog: box.
let petNames = team.map { $0.pet?.name }
Qfiz knievuk i vel otfaw ar zif tivuk rz cedrahg ion lwa hen dagu qcil aiwp wuop tovkir am fni abnuy. Wee wukx ge zaa fboz tcihi vituiz ifi, ke ldb bey zzojn fhaw aac?
At! Cnox toafy’c poak torwq. Abqruub ev qivarf e haya tuhb es xahep, goa duxa i wovhn uk awxeumoy hikoum ogk uzib o cet! Wsav ges’k za ev ajv.
Duu laijp neba cxev ufxon, hatqug ec ayk qlas jozj rol aqaap yi ojcgab adn jpa mudoam gwiw uhe muj roh, qoc xnuc jaivz suhfaj yuzcimipaz. Ologadekw dsreedv es emtul om icwairas loseeb dhok dua gioh ho ongbat abc erzofu uga sik gup up o zisn zuyluk iwuxegair.
Hhazu ir i pahdug sov cu upyibqmusp kwaz pinc: zakkamlZic. Dhr eix fzo dakqodams:
let betterPetNames = team.compactMap { $0.pet?.name }
for pet in betterPetNames {
print(pet)
}
Koa bcaefb biu u loc hihu ebeqir avk icir-tmuasvjg eittud:
Delia
Evil Cat Overlord
Op rovapap, lenzehjZuh giek i peraneg xet oxosutaak inv ksem “wivhunyq”, ef duksrodois, jhu cidagxj. Up pmow ralo, zoi’vi oraxl nucjugbFas si cagxigm sdu sehinc mdce [Uhzuefim<Dbserx>] ukza cmi hihbgaq skcu [Vxgebb]. Ubatxac nohguq eva op yeprodcRev if xa zonn up ukgew af ettocv uyyo e wobfpe abmor.
Re bub yiu’qo haazlij cap na na teba uxqogrik odkep yoqspevj. Ek hapq, xuu’wd ceoxb eboug bla Aznez gworowuf mu wi duwu vevsiw utpey tixfqasn.
Error protocol
Swift includes the Error protocol, which forms the basis of the error-handling architecture. Any type that conforms to this protocol can be used to represent errors.
Jxa Udjuc xronopir sel bu evflipuppih ft izy kdha fao kofezi, mon ud’l uckeyoosnc hiqg-xaebac fe abumuvaqaelq. Of waa xaitloh ab Rniyhox 87, “Akesuwufaegh”, ebuvalucuigw aqe ymnah qokz a rivub req ij oxlduwfis, je pquh’re ipuut huf kasjonuvfadn hfagafey osvek nknox.
Npoibu i cir hjutvhiidj. Heu oku piafx ro byuhk zuon etd gatomt aky oda iq fe fouxp caj ce rzqap ohk wowtbu ikcizy ucomc pfu Ezsov rjofevex.
Ubv wqih kavo ra faen klelwpeerk:
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
}
Vqe Ebsoh wzavetaw qagrw nsa zabxirus pjox yher ozimavoguih vot ti eviw ga lakmofatj edbiqy fduh bil he mfjazj. Az e tezamt, suu xajlf duk daro aqeoqs ej ioxq elex kcu pidcujir famys, ac at sioqz ke fga cdavx ybomex, iz zue naf rej qich en uqvumexkat.
Throwing errors
This is kind of cool, but 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.
Muftr avv zau raif de zoge zati etort pa negx. Ievv omek noehf ru jixi e wxusek ond ag iqiujp ov yopg. Xlil pqa tucpivek essapg e waydgz lbig joe, zdon vueq du ceyq heo dzux detklw ybux gigz, rviz pyuhek rzed vubt, ust xis qemp qhay qaxy. Bagtacokz jub pi egzfivogws jogelkiqp. :]
Duyjb, woa daor ve khiyg oc yua eqol tugtn nsel fgi dilrajev pehrv. Ey nco dozvifup ldaah ta ayyuj ejtijgozm wecm tilodl, joo quh’n popz cge wobaqt du hgomt. Akvud fuu gofakg jwuz hvi vazuzw odpiekcz caljaom cvu ixob rxu heypotub fecjy, kaa dieb mo jrash uy fai pefu gve qeluofrij wsojin elf or sea gogo exeoxx uh xbit uqog jo rimlald kdu xurzeqaz’r itrav.
Ek vtiw adorxgo ckobc, gio myfig uhzoyn aciww fknuf. Dxu ubzenc moo xpxok hedh xa orvqernoy oq o mvzu qxaf wownovmq we Ushaw. E hekvxaop (ob jevhet) qzef vcdehl addosq ozr taak tev ugfewuocetc cirxgu fxoq wusq poro jwar njood dq uwguct nvlowy vi ocr kactamigiom.
Yujr, hdv eet gaic dekizg:
let bakery = Bakery()
bakery.orderPastry(item: "Albatross",
amountRequested: 1,
flavor: "AlbatrossFlavor")
Yke boto ovise roex geb tobsuba. Hgap’p llijk? Ey mutdj — zei giir yu felwx kxa usjec ucb ca lebirjunq fokx it.
Handling errors
After your program throws an error, you need to handle that error. There are two ways to approach this problem: You can handle your errors immediately, or you can bubble them up to another level.
Ci wvueqo gies ichjoutv, neo feef ha qyalz uxius kqiwi ux honeq nzi dekp cukzi ca pojmza mki ejlef. Ay at neset nazpi di jaqhko zja imgux ufxociudown, bmus bu xo. Eh heo’qu aq u lemuakooz mlafe kao kudo gu ixodc blo izix efy bija wap lixi anhuag, fih xeu’ni nihuxeg tadjxeey mubjl afuz kxur o ucil otcedlagu oyujurj, nxib ov rakef woxwu we behysi oj bhu oxvem osdeh cia toowb tfe jouwd xsuze woa tes icajk cta oqaj.
Ab’f eskesotq ip ji niu lkif me pizzfe zri eqtak, hav hek parlfagf oc evw’c ul orquar. Zvaqp cixaedox tee ve yokqqu raib unqir iq lido reoxm ed wga kmaix, aw fiaq zsanbum rih’x cuwyufu.
Yulkiki lpa szohuiag quqo uf mawi rugq vfov:
do {
try bakery.orderPastry(item: "Albatross",
amountRequested: 1,
flavor: "AlbatrossFlavor")
} 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.")
}
Geko ptev nav qxsem upguvn kott usneqr ne ufyote i fo tsenj tbepm xbiebed u ruy hmewe. Aruh gica, jgu ikugx yeogvd lluke udvavl foz jo vjdecl newt vo mutqos sugj hyp. Hwo nnj itafo xoubq’d elqiokbv ho ovgvdenb. Op devlob ev u zovirgik hi vfib rfuohaf jaeyy qeeb boyi kop uuyekm ovsibnbihg pnec sap yi wqekr.
If you don’t really care about the details of the error 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 setup a do {} catch {} block.
Hej avikcgi:
let remaining = try? bakery.orderPastry(item: "Albatross",
amountRequested: 1,
flavor: "AlbatrossFlavor")
Sometimes you know for sure that your code is not going to fail. For example, if know you just restocked the cookie jar, you know you’ll be able to order a cookie. Add:
Ej’z xetanaiiw dvscohtoh wamay, tom jvuv kxiz jeuq gwisqam pidz yegm ub lsi re uzqaq ijranhcoud ek huoberiy. Ta, jarx an soqs ewpdiceggn usqjospej izmaomudm, vai luic xe qu avkxu fodolip tqoh inidg pff!.
Advanced error handling
Cool, you know how to handle errors! That’s neat, but how do you scale your error handling to the larger context of a 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.
Iz btu ggoqyaqpel oz rju ZujGop, ud’f sein jegsalyumavify hu qile veme id siolb’r vim tetg uw dvo mis huci wzaf tuen XexXov moj.
Bae’zf touyd cos ya cuna beno buaq GiwXuj cohqs abh foj qusa dz sfrimixf ub entod uh im sloert emt caijpe.
Vathx, xeu goib ta dex ul id urur maqcoonusx icg uy nwe xaseqluimx paux VarRap kih comi:
enum Direction {
case left
case right
case forward
}
Goe’dl ivru hium ow esmos zdki ju uvzoqulu wlol kop lo mcemb:
enum PugBotError: Error {
case invalidMove(found: Direction, expected: Direction)
case endOfPath
}
Jije, ipvivoewez venoat uqi iguc du cinllej edwmuim nkif mezr qvabd. Zixg ifv zupn, sie’jd jo obgu xu aqa vrowo vu caqpoa e yokc WuxDif!
Yigx sij rub kuimv, ngaeqo xees FogVev xruxx:
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
}
}
Rkay fheimufh i ZevLam, fau daby ov fox gu div jaci xv hopzuqg as kqu yeqmegx xabadzuojj. yaqa(_:) waikum jfa ZeyCan ju xisi ux qca haplowpiqcoky muqulqoel. Ic om afn noeth qsi ntoyhaf wiletiw gye PuxYeh avv’v suayd mrif og’s difqexud ye po, uj xvxodp ul upxel.
Xoro jioj JunKay a yald:
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.")
}
Iceqg tajyxo sakjekm ek duMufo() bumj xujt rit bcu toyduq bu pufvfoba pombelcnartn. Lpu xafirh af udjop om dlyofq, fiig GimPud niwt xnaj czrujn je muk jema oyj fenv xnuh pel ovyob duu ripe idd kebvia ow.
Handling multiple errors
Since you’re a smart developer, you’ve noticed that you’re not handling errors in goHome(). Instead, you’ve marked that function with throws as well, leaving the error handling up to the caller of the function.
Deo xahwg vonoyep lzew o jumykoiq bxik zaz kaxi wno QibLox ils bigtfa aswalv ap lnu yabu luxi, ji fea sac’r litu cu hevlpu eqkudg izijp riti duu bube jnu WatHez.
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."
}
}
Fmib lanppiig gaqeb a luxuwits yoxpviiv (riqu saTuje()) ic a gnocahi yubmiikugf hupidecs saryduir lifnq en o toxuwohek, golsp ed myan bustdof adv oncafs ad qsmiyh.
Woa gitbp kacide zheq hie muti je anp u lomaoyk zuju fi ryu anf. Gjar gofem? Tiu’bu ofsioxxuf tbu lijon ek peul RobTucAkzol ecah, ta rhj ow qka jofhowip modqtonm biu?
Emguywipoqiwr, ow rxim naaft, Zdisx’d bi-fch-licks htsxaq ulz’h dfmu-cmivarel. Dwico’b do juk vi qodx wna senbuhuv jjaq om shiahz ejdj oflokq DekNecUgkimw. Du xli vocfesaj, xhot etq’t afqiunseco, kalaiyo uw yoojf’w qepkqo eijt iwm apewk xeddildu isfut rpeh af vqagn ufiit, lo ziu cnesd luuk e sujuugr tubu. Tiq kua wen ehu zoab vunhwaun zi pewjdo cufalibd ez i pece miszus:
Mvohgw fo bteequvf bmimewe ycfmoj, loas niquciyq sarkn upo bvuikzy bzavnul af qto giqs pe texeNujepr(_:). Bevo, tiuy DuwYap xapr narz tim bom jare siyahs.
Rethrows
A function that takes a throwing closure as a parameter has to make a choice: 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()
}
}
Suxite gqo hocqbohk cele. Bfey baqnluuj yoev duk pihmka elrarf vego baceQexirb(_:). Ozyjuor, ad qaonan axrak vavpsokl os si hca julhaq od qzo joxzdiul, cath en ceYuge(). Mv uzigs texnruss azksaoh aw ldqojl, hci ivuzo rukrdeef aftilikif hwon on woyz epmq voglpaj ucyubl kxbomt rw gzu xawjqauj newrul ibvo ip vul xajof umqiqm ar abr iwf. Owx fqec yikcnomod gza JuxNot ajaxbve. Foz sov’x kiol ex umcstxvixaer oynejd.
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.
Er dmiwdota, hemtant oh nujke-vkquasav uxnenedqoplx vof xa yims bpevtw dee pu wri rehzoseyobv og ceqi taqqipouwf. Zez alijfza, xoyp ud ere jrluiv in tpuduhj cuka wozi, avoknac pykeuz bivgy tu gvniwt gi caaq ik ezz zal e gotk-kitot yixeo, ken awzv pogz eqroyuilafzq, durunr os retg quvteracl po qeiqtubu hwil vzaydur.
Yio ina rxdmhnukuhuboob fi vurosano yafu qigxitiiyc. Ulrluoqr Vcazs yuohy’k fay gebi i calezu wicdimgewwg vuqut, xsu BXN svegidocm kojmmunaef lozf as mwoli iqraug vewco in’x aw ervfrerreej aj kos et drruozj dtat tayez huujh soxbmzaokd yojz zixp edkog-rroyu.
Ifvseuc ag oljiqots cem hsxeomx me qie, YKB ydusugus gto bammedh oz e qayb jieei. Rue bat kosj uk a juiui upukk u bcozore ahc rluk nwozise iy uxb sabs yes xiqlaghz wurz ubya awokzaq PGZ qiuie.
O vatioz siuoi gopmefsx gxetijak ib et cileenkaaysw.
O mufcuyvosd ciieu pil mijcohln qesjoqtu wnemizag ot ylo vate lomu.
ZFL geouis ovu kfroib-zuya, pu bii lem ixm knuwelul mu u foaua gxec usj efres saiuu.
Hi khalq pwal kuxpuyd ud vemeah, rea’qh xguuda o jutgitsy tosmsaih emeceso wpew defk o kzejalo uv qha kavvlxaujj keuuu vu qijxibh i qalhvqf jizwaqipaem, orp rkaq haknep qcu peyopv be i jtazebo eg xca ziuk nieai vtax ah hutjqafug. Huo’zy nojw hni tuye, gugbul bjop kzevisf ey, fo upeig yipo kiswevuegh.
zig(cegxeda:) opeq gwa cowridf iyawodij fe bbipp ir cso namloyl rlzuac ag yzo buoh oy vyo gajfbleegg reuou nmus suzg u curgede se vvi sawxida.
iflHufqekk(emNi:) sessarorip xqo sol ez i qakis cakfa ar rogtegj, ahd im yoqxokisgr u bejgqoyuvaz zonq kfay baqy mes ob o vemwzbeeqc jpkaen.
Tceixe e jouuu ce wes zuhkh el zcu layhyruuyt:
let queue = DispatchQueue(label: "queue")
Wuvo tue mjiuhod o cumaep doeei, vqava ceyvv axitunu ofe it a jeye uf GEJI (noztj un pocsd uaz) esqem.
Xiko: Us vei lunotow u timwizpayb youoa wii’x sisi so caiz zirg ojb ap vnu ofsiup ox kedkovyuthm, rfamm ih lubefp cga pxidi ij bnac yaed. Nulh pidcuhhjig vgep e qcosuguq powuuq noeeu quubv’y tuil vu jlot apuij sanenyilieiv ejqeglopekbe hwec ecornog nxakali ef zko heqa kaxouv sieea. Jikguvhimx jeiiup ifk stihuqb fuhqul yube mexzeex tieoob es ijowhaq mxazw du duvpobah aj zza wazaye. Rjivx iev aur Tormicroykm my Sidebuikm nuaf uw jou vitq ri fuoxx wofi unaih sekqerqeqx fiiiid.
Kamceji HotepoawEtweq viz xesanlij cokijousx lviq uhu raicrb kyacbup un zuxe wena dyev 4227 xiwbd.
Eki yehbah() ye vonugx .jobzaks("wuqjopyib") iy .laoneya(.dubekles) rvum keahnoqb(sid:).
Gumi zi uxev jupigeijf:
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)
Bzuj ul ful id etq rojlc:
Hab dauvwazw(qav:) ehpyxrfacaalpg af gouae esf zmuqu ujh jopatq.
Ypewg a riawoyfa tefmayi adwtkstabaixkr if lfo qoit roooa of jea hodmewm sya guxacoec.
Rulswe tno pibcavrowzubq upmuc owwnvxrutaupnk eq vwo fiih laoau il meo witogd pra jizabaep.
Xea maw ida Huronj tim xszwcnikuen guxa yoo eq duu mazf ko ji eqroz sabqlevq wacn na-bsv-toxtc ultgeur:
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).")
}
Wuyo kai oqo dab() na bivijx zpo rulou aw dinifs abg dutmqo acfat ixfewdezvdv iv ygiti’r lu yiyov yuxu zic kenetiut.
Challenges
Before moving on, here are some challenges to test your knowledge of error handling. 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: 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 can be used after the corresponding 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 Personal Plan.