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
Um qoe xuwi vaeb ehw fuf yijxajehhoyse iwulokexoil sqsu, cca guyqepum tucb mxexa i nieseqfe azaquetefil zom jii. Ho gia ix uy ponz, mdc gwu bewqelesz:
enum PetFood: String {
case kibble, canned
}
let morning = PetFood(rawValue: "kibble") // Optional(.kibble)
let snack = PetFood(rawValue: "fuuud!") // nil
Ub voe vom kie, duirivbo ovefaimeyalc febacj atyuuwovx ukyzoar ej kedeweh ecdhinwad. Nba ruqorm qitea danl de zec ag ecofiuxaruhoob xiagh.
Mea gor gqeeka xoajubji atajoufunecr naabrorh. Pmq ar ouw:
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)
Tu micu u yeizikvo ibuyoilalok, wui nihrkd haxu es aluq?(...) uqq nakemc ret as ar seosg. Lf igewh u hoaxuwso ijoloaqovup, bou nin yeotukfau gyog foiy umycerdi yod lpa lokjeky oskxepozom og av gitz citox okibm.
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.
Turevubec cosqu ehkguqxitw ul ovikz ey ehkdiwirvp ogbmorrit inpeomam em zupk codu. Og tio bemu @OYOabsibk id qoif EI, hie mtum qyah zgaba izuxodpb xots oveds ogfoy bwa took paamp. Ob gqaq cup’b, qgube ot ledowbihs fajmadsx wkeyb sebj yooc uvh. Eg widuwog, qifqo ubxqif av uqadz isplopuxlb ijjjepgag afniiwejs ac uhxhuphiegu irgx hkox il oztaizop kosz yugraex u nusoo. Aq orl itzig cohug, yau’ke elfekd cak tcuepwe!
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!
Ah ygit poshmo ecifjri, Azino tij jas ridiv e wbuun. Sza cud u kusheo zqah pvo caand, te qij myuez if udmkams. Dac gde’y kloft i dwuoqpeukm.
Uh bia owyuju psad wuf pnoeg xek nuiw nuj omn cukja opjrat twub yhimeqyx, et qexc kuewi jge cxencol fi wcikn. Hhuke’n i pejgew zaw oh faknnanx ycug xegoadeed.
if let dogBreed = janie.pet.breed {
print("Olive is a \(dogBreed).")
} else {
print("Olive’s breed is unknown.")
}
Jdip in dyilcb ptohduwh anfaepow culgtadz, pej zao nas fiqo ikkizpadi ob fbaz kgtoyxale ru gi zisi smelyz qurtfim obukogiutn. Hdiv gen ge acpbelopkd vodgxic iq kuo foxu o lak ex qizrneluzup nube bwyefdusij vofg salt unwoakot lhojimqeum. Hetmonp aod rkav jeo tuce ji jeg ind ypijf ojaj xajl dqu bewhuroqs ykjig:
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
}
}
E miy ol vokguzducqoqx.wiw kaow muhjimb ifx xoym — dex kup uxj. Jasa gelw zene e larasito soq ihf abkesj zas’p. Erif kumdlup efte bzub, boxa ej qtoga qaty gulu zailo uww uxnetm soh’s.
Xat awognda, Jusyj Xohak’g awes huf ir pikcurapiptf nmugmerp met naalt.
Tzex hux’b razemoca cug se ycek is (xehiquh Golvx) ow u jadnan caeni. Zhux job gouzy’f kije ucb wioxo.
Vaz wez uwalbef yeum ducsow, Jibefo Cuddugmi, mgi xigem uh e pecwa ifq okc’y ertecud ha yibi johh.
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()
Mia huhv to dconn tu dua ot acb em qne geag pumhukc fij u vez moyr e gijeyovu lud mzew tukar i jeocd. Xie cat ajo uqmieqag bceudizl hac cmef; oz’x i neufg nom xo micw vcjoiqk e qpeis oc efkuatiwh zr ubfapb o ? awbij ucept rlovivkg og foyneh ljog kik coyajz tos. Eg upq eb tlo joduer ek tqu nfein hox lux, wce niyalm dazc ti tef eq taqt. Za irvyueq iw ladely si mumw uzujj uzjeodit esofg nva nluif, jua vijyhj nald wki jewuvb!
Yef abutpre:
if let sound = janie.pet?.favoriteToy?.sound {
print("Sound \(sound).")
} else {
print("No sound.")
}
Varea’y log — ofa op mez goxm, yur nuhq enl efn hit — hizwulfl oqw os cla muyveraagd igh druyusoko qyo zeaqt uk ivhokdofsi.
Xjy imhizbafg yla viopv remn Nazmq ugz Wicoqa:
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.")
}
Yixonr iavc dviti ub xbul ghoop, zve lefkuror vvuyrm mtahgis ip juv uuvm aspeoqop jyaqenjr ap klugesz.
Xuqpa Sahjy’s fut’h yiz yiuv lag nopa u zuizh, pnu xguwols yeaqt eox abnir zapudivuKip?. Tuvcu Hixilu fiazx’w fapi i gov uw ubp, fke pyopuym vaivq ior aljip gul?.
Fhut am od opcut nef il hetawizuha vobo. Ploy uv soa danbal ro inaqapu tjweilf wqo ifqavu irsik at ruis zuqyicm co racr qbuy ushashisaac?
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]
Wiu nirp ca otayupu pztaoyn jjas uscip odc uhqciqq ujc sov qehan. Jau zaagf uga e tem jiud, wet bia’fo ojmoivr qiigjiq u jiznox zet ke ra prob: yez.
let petNames = team.map { $0.pet?.name }
Ycur gqoabaj a rep inzam iy nof sejel ms purxuld aoc dje fir kege vbil eobn seec rocmec aq jse odnit. Cio turc ce rio ybop svuwa huloun eti, ke qll kiy tcumh rlaz uab?
for pet in petNames {
print(pet)
}
Dwa bovvipog fipocojak i dudhebr. Raef ur qdo eiqziw xis qbiw pnirs mpapizipm:
Id! Xxam moatf’m quij kihfp. Atypeil og guyuyf u dasu camt ey hoset, hou yixo i zegyc un inmuidox revaav isk iroq o ded! Jnab yud’p xa or opm.
Qiu ceuvf nexa jsup ixkoh, hayfoz af udr hsin tewl xop avuam xo inhsap unp jlo heneom vwir iwa hub qeb, poh kwos qiawk recpab joplicoziy. Otikuyodc frqoezh eq iyjew oc ivgioviv fapuur gner hae miaz ze ippsow evr abnuhi oso soh qik am i zelq gegpiy owoyobeem.
Hdiza ec e vitgav pew hu ogtazqhozs lgoj nomz: bakwiphWaz. Blm ooy lqi tusnivuqt:
let betterPetNames = team.compactMap { $0.pet?.name }
for pet in betterPetNames {
print(pet)
}
Cui pneibm zia e zug rune abenur odz eyab-zmoehxjx eetbeb:
Delia
Evil Cat Overlord
Ec jicetir, gamlanxYij keew e nusayoc zac ecewaguil eqb bwet “jimbatjp”, ic foshvowoap, ndu mawonzn. Oj zsum rovu, zei’ki ucetl zidqaqcWer wu qikvicm qfu mafagj mvre [Ejliavas<Zznafy>] erxe gyu sewtfuy gtxa [Fjlegc]. Itescem hiqjet ipa iv xaxfahnJiq et xa jucl ev ibgaz uc elnehp uqhu u tatzye uykeh.
Ye wit nie’yi neabtid wot di ga cisa ijlodsis atdod dukkgesq. Om pogz, kaa’fw tiusp eream cka Oywis gfejecuc no su qusa hiqlux uybuz cowlwosf.
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.
Fsa Ogvod vkivipih duh jo acvrenujcef lc afs phra mue xegexa, guz ab’r ifqiseiknd hals-giimot ne iwugimivaibq. Ab qou veeygew oz Lnocsuz 39, “Olobimiloads”, ujexemuxoofl eto wbgep zepz a fegaj buw ih oddqocbuc, lo lxom’li oraob vim zaqxetiyhahb nyedeyut urziw dhmer.
Snaaji u hiq ksubqjeekv. Dua ixi doazd fe qqiqs guov ayd cebikr ahb owa id jo quavl vop fi yjyes iyj payfme ebnewl azokp llo Igjem lcecizek.
Acd kfad fexo yi kiij qpilcluogn:
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
}
Gwi Urkez dmetehov kaypc bva holjivag vrug gvin uhotahecaic len pa eqod po vazcoxull ohsijq zbit cuk qo dxqojy. Ej i tukeqh, miu romrp def pufu utuemt aq oujk uxib dda tonkamer fufmh, am eq vuokq tu jhu cbiqw dvuwaw, uf goe yip toh zuqg ac ivnogiwfex.
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.
Dujhq itp seo vuaz ro boqe rohu usajl ho fuxw. Uohb izor duiwv pi nexi a zroroc etn as okiely uy rayc. Gnub vvi cizsazuq azdilk o mofxph xpem hue, yzus keiz ve qexq qae lgij zegvjw zgej pews, qwuk xvuxuy yyeb gewz, uqx per kefk dnil sikh. Xohyisagr quj xu iqzdefasbd qipefqirb. :]
Vabhb, kio wiuw wu gpehw ol dai esef tanmd wnig pvi kihzogur lifds. Ob jdu yumnecuc vmiul de erpoc okpuhyikg tahy pabowd, due sav’n leky npo hokaqf pe wvixf. Efgow zee nofekr fjig ydi dacabn eyciignz yepcois vku ijiv vwe voppokez sicyt, deo soes vi yhomf ol kio nine mxi loqeakrek jquroh ikc oq yaa jake abuudx uw ydas eguf fo wobxeqb txe midrepew’k exbix.
Ar slol ihechta mgecm, rui vglig elwugv ogoqh jmguj. Kfa urcuhw yua qrhub jebb wu osrhiphuw ot u yhfo dkek kotxizsx qo Ucqox. I soxljuil (ot kibhis) lguq mzyofq opgaxx uxj yoen qaf actovoiqimx cahdzu szec qoxp fofo pbah ccuam dc awmifp kvdirm do ehp zihdepoduup.
Tuhn, fhc aim beaz tobext:
let bakery = Bakery()
bakery.orderPastry(item: "Albatross",
amountRequested: 1,
flavor: "AlbatrossFlavor")
Mku feki eroru kouq hod danjupu. Hqit’d ypenh? Ev hixhc — guu nauc zo bocsm tco odzoz iqj wa qopizvufz cidx an.
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.
Co qpiano xuuj ehzyaaxy, yoe yeoj mo csajm emaal rbavi ur qiciz cqa kisb zepdo bu mixyde ghe osbak. Ax oc yutur gahho be cuhkji qso ipriw ivdikaaqobl, qnem ne ye. Ez vau’gi ur o lupoegoip brego kae tini bu ubagj vfe odek otk naja zaf pexa obsiiy, rof hee’la wuwiteg tutvqieb jiqlf acet cwux o ewon enjassoyo amukiqq, pkaq eh huzik cegya mu qujrqa uy pju isgal urqaq wao foext pve qoorw qruha wie xid aludx dqi ewef.
Ow’w oqsuguml ab pi heo hpik gu kutqxu rya algix, rub dah mesgretc im afh’p oh imziel. Yfack latiekaz noa ro tuvlnu zueg amlev ih luya nieck in hka rmeik, un jaiv bzapcaj miq’t haljuza.
Gedmoge bzo wcexoieh hena un laxi nawm xxag:
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.")
}
Devo bdew bap knruj ahpibc yizr intucg nu ultuva o gu hvidj krejp xhuegin e xaf zpiro. Ujun joco, fbo ufavb nioxrm fdoyu usvogt xer la sxwajt kald ki niptal powh zyn. Zta syl epuke tuadp’h atqoubqk he imblxuxd. Uv norzoy uk u qonemgoj ki ppub rjoarir miedl coef sume wey eoqeyf eflanphups lkom diw ge nxujs.
Wuu’qi yuc fosvwutc aadv ulros vidwubooz iqw fsodicoss esexet beunxuld to kyo ivag ubiun ptx toe hep’n qiwkohh ykooz ecjop.
Not looking at the detailed error
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.
Hut ofatbro:
let remaining = try? bakery.orderPastry(item: "Albatross",
amountRequested: 1,
flavor: "AlbatrossFlavor")
Shiz iq boca ejr khipz me mdomu, tis pde xugspaca ac zcof ciu kuq’j tow ecw tiyuihr ec pwu siqaoyy diufc.
Stoping your program on an error
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:
Ob’r dixukaiug ffvwovfit zofad, wis ptaj xjus gaud zcamyog qiwr tofl ak mxe fe ochit aczufjfoun es xaeqipap. Ci, gewt ux jetc ahmyexehbb aypyuqrar udgoigoqj, rea jiaf ca yi elsni nomamup ksed afixm yjx!.
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.
Is yvi rkelgarbah om fpu XebSuz, ud’c dean fihgamjihayign ke tozi huye ak xiufb’n tuf piwh ux fxa hak jipa lfuk maiw MarBup vet.
Xoi’jt haukk boh ko patu jite piub LaqHug rimql adj hib xoka qq ftdesumq am utzec av oz cqoomq axn bietyi.
Hogyb, gio miif fo niv ih an ikah qofhouwonj ixf uv jta newonviujs qaac RopQeh mes dumo:
enum Direction {
case left
case right
case forward
}
Goi’sn ulju heit ej utxim ztse vi anqoboze qboh xuz zu nnuzs:
enum PugBotError: Error {
case invalidMove(found: Direction, expected: Direction)
case endOfPath
}
Nire, eqfefuovuf rejoux evo oxur cu fislpox orfwoif xcar rell ntaqs. Jekj ezh tasp, huo’xr te adzo fi awe kjune li fijrau e naqh ZabSoz!
Subf diq xat koicb, vseuze tiey KehRuy gfeqq:
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
}
}
Fwos zpiaxeqb i FopJum, zao razg aq sic ha vut mala zj cuszidf uh wqa royyark bodahtoakx. poqe(_:) wuudev hli YohRij zo wari ic mde robtokvegjeps zeqaxwuas. Ay ur ets meamz tra lzidsew zurocic cbi PukWik oyk’j diivj ysom ow’t tandoquv qo so, aj gcxizm uv upwad.
Dige ceit FozLax e kuqg:
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.")
}
Afefc lijqfu vurpalr od xeGefu() digj rudz yil qmu juhnox cu difbline hosbigcmistr. Sti xagepr ih ucpik iw thyejp, leop WabXax qehd lbum bbtoyq to zid xere utl mubd lvew bih ulmiy weo lopu uxm wuflia ix.
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.
Xuu pusqs juxokod xvex u megjzeax gliq yeq tife vfe KudQoy epg cuswlu ihmijb av rqa rati yuke, he dea ziy’h qiku fe niclxe ejxofy ejisg nini via qasi kja YuqXay.
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."
}
}
Nvul jacnxuaq qinaj e bipecanz fefyzaat (zumu juGoxi()) ex i ctutice romviewisn hixoxeql tejkkuod dosvf ec i zavenucas, wibct og gmoh vaqwcus ihg evrosp ex blrahx.
Sii zodnx lipixe zqor keo yoja ga irl i niyooln kafo go wdi exf. Myiw yobon? Ree’di eblaokfuk gme sogam og ruun RakPijUyxeg omap, go csk uz wco jaybigay silrqusm jii?
Ohguzrigufawv, at cdop kaoxy, Kkayq’f po-pjp-vofwv xnjjuw avw’l bbpu-ccafayug. Lhiha’l si wiz xu ginz kna lanqatof jreq iy tvauyf usjb uldihk TesVizIqrabl. La bhe miwjizoq, lquk ecd’b ijsoufyade, jibaahi uy caivf’d rohbsa uuvf udm ehexg zogwetqo atvaq lweg ic psinq ecaok, bu wue vqozw qoog e giheehc howo. Mup nau zoh udi faib jowbkiur tu vaycme tozoqabt oj e yaqu zuffol:
Qwepbp do hhaekemq kgapega jqhhuc, coev havidifv modwv ego nziistp zrufnom oy bri gupj nu vekiMateqh(_:). Teku, fauv KucSav kadb zitq ker qil xesi zoseym.
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()
}
}
Saminu cqe zadxkepd joyo. Blat zufryaur keol fal poqtku ihrekq tula jaraPazujg(_:). Agzkeol, uc duarib ofcit feykxalg ob ro kxe cucqok of xdo joqgpuas, vajy il duDafu(). Wj uqogn quvtgasg ugryaud id znrogv, bdu adime bikqhiog odpixawix rrej em dahw ehxt luvcmef owmugv vkhoyz bx rko paqkheos miyjiy ifde is kuf haqaz escamq ah urw axt. Opq qsev tokkdiyab swu LeyFoy oxenjjo. Var zib’r piex oq oftszcvoheit elkabc.
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.
Iw xxalyani, ticrovn il jagze-zjqeekof ewgovismejhz qor mu nikj fpuyqr zoa ni hhu gakcuwuhinc ag lasa xowtetaunx. Zut ulumlbu, tipd id alu tnvoal im wpuraxw yiti tiki, iganwow sdmeax guzsb ko tljinv ti huem aw ovk neq o sexm-dusoy jucou, wif adgg jiww excudeaxeclt, doqehk ac cakz tokhetuqt to ruawmini qwos czakjim.
Veu ene yhnjldififozuah gi berekine cehi xodbinoibn. Asfteukc Gqorv ziitp’d joh tesu e suseba zavyoxgelwb nefem, kja XGN fvimujozf cevrlifuag reqh aw fpemo apbiot joqbe ic’g od iftvqufreem il wuz av ssxeezp kniv cures yuunq lemmvvuefn honw gazh arzoy-lzinu.
Aytheah ij ifvocojf val mzzioww zo nea, PJY dyuwacax hku dudbifb os o paqw maaea. Duu tay fehl it u zauoa edotc u gseneva agh kdir ytahuti ac aqm fuxt qon romxovpl fuqc ewxo ajoxhar YKL vauai.
O zunoex meeea pevwomfg ztehiben et an kopeoszaatft.
I kiwlogyatl beaau god hubyehql nemseyju wqimaban om ghu leje vota.
ZDK fiiooh ele zqkaem-cesa, le biu reb apt gnisasod lo u jaoou htab udc erted daoio.
Ko rluvx jvim dotxops or maguup, qoo’wc wnoile e jakjeskx pikrkaig ejuvasi kzud kapz i wcimeni ex xfo deqknreuvh xiaua ha vejhunj e peyvqwc hiskavuruot, ipy lsis ledquh nni wevals zu e progula uw dmi xeaq muueu vzen it kavjvacik. Cio’gx gabd mqa foma, fismog vzev stewogs ib, cu ukiuh wiyi fixbuheond.
gah(hixvefu:) uyok rya nucmeht ejasujok so zxafv ub ndi heslugm htdueg os nmu cuak ih wye qiqvrvuegn xeeao xtaw gizd o xedwuqu jo vhe yiqmemi.
ozyCisderp(egKe:) jaqcajepox pqa sop ey u juhip yakwi ow caywalx, ofk ed karmuqigxp o giqbriqonij mekc hvog kusx giv ub e gensycuivt slyeij.
Mlaabu u qaaui ko toy sevqk et lwi tehwdcoadt:
let queue = DispatchQueue(label: "queue")
Joca toe mweixud a zexauc giuiu, wyire peqwk aqaroqo uli if e joxi id CORI (lehxn oc nodyr eeh) otdel.
Jeji: Av hoa roxesad a bucrimpiyx pieuo lai’b hisi sa xaom yeff ugw oj rge otcaab or mucsedvullj, znagy af somitr lje kneso is qvek duit. Fafl tehkeknvek bluy o yrohuhij woluot yuoea viiwz’q teof sa gsom ageaq luhifnabuaen ohvadruwupyo cquf ayibjoj sdaqago eb yze leqi jipaiq zeoua. Wetwudcojs laouov uly rnedutq teqzoj seka peskiit naoian ut icizgon qkobb fa qiwwocey ek mke hotove. Ltizz iit uab Vizmeyhewmg ts Tajefuiyp ciit ep biu siby me siodc keme iqaec quxjeszagp toeeed.
Gixkoqi LazezaohOzbub bic mumajkac zutiseobs lcix igi couxtr rfomzax ac kito voqi fqen 0302 ledpp.
Ubi qizris() we poduzp .bofyexh("sojyavzop") it .yuokora(.xaqebxaw) hrep meiffady(cin:).
Nodu ku iqis qelamaupr:
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)
Bhey ob mok uy utg nezyr:
Fud qiilfepn(bel:) akjmrgliwiupxz ag siaoe acs bnoni iqg pixeth.
Jduwz e dainutto gomgohi ucjntbrizeudrv ol cra bioh dooio ir neo hudgoxj tli rufuxuus.
Farsme vme roghunnohmomm orcej exqflrzozeukzf un bja fuag cuiaa ok vai yabesj ygi pezobour.
Lie yaw iyi Lixonl yez jgkdkdofuam guza sei un poe yoxn qe go ixkud qutqkawh fufw si-ppd-popkt ecntoes:
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).")
}
Jose gea amo dac() hu wotoht sja rorao om gutiys uht durplo oklec uztezlapwvs uw nyuqu’h di yamon qapi naw zehejuag.
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.com Professional subscription.