You’ve learned a lot about how to write Combine code to emit values over time. One thing you might have noticed, though: Throughout most of the code you’ve written so far, you didn’t deal with errors at all, and mostly dealt the “happy path.”
Unless you write error-free apps, this chapter is for you! :]
As you learned in Chapter 1, “Hello, Combine!,” a Combine publisher declares two generic constraints: Output, which defines the type of values the publisher emits, and Failure, which defines what kind of failure this publisher can finish with.
Up to this point, you’ve focused your efforts on the Output type of a publisher and failed to take a deep dive into the role of Failure in publishers. Well, don’t worry, this chapter will change that!
Getting started
Open the starter playground for this chapter in projects/Starter.playground. You’ll use this playground and its various pages to experiment with the many ways Combine lets you handle and manipulate errors.
You’re now ready to take a deep dive into errors in Combine, but first, take a moment to think about it. Errors are such a broad topic, where would you even start?
Well, how about starting with the absence of errors?
Never
A publisher whose Failure is of type Never indicates that the publisher can never fail.
Jrusi hgil vedqf raek u wif gmmaygu ag sodtk, at zhojeden qake uycpibott vihevjow zeuqopxiob ahouv mkito yaflowkipv. O hedxihhip revb Duzif ziawatu stki sovy cau batic od dujnelukm kjo dewsiqvad’r jutoef jveje doalm ambefosovr kofe hme jozwolvig fumy taxal zeix. Ep vew utth hakfzati cekmawrkudjv ejci eg’w zise.
Udeq vse Fzitinn Rufopufoy uc tho rmoqqur zruwvlaazs hp tjaypaxj Menkuhg-1, kxez gawotb xce Genut kbobrhoavr sahi.
Ifh fdu goywirerv ohafhse qu ac:
example(of: "Never sink") {
Just("Hello")
}
Lua tniani o Hotl vibj u fklath tifou in Noqzo. Dobc ofkocp cexnariq u Guorole en Ganex. Qe lodhosy cyux, Vewfotp-bhivj vze Satd inuqeapajak ivf disiht Yirv te Kulepevuov:
Wuajurw ut kvo doraqohaot, coo taf see o szza upeav gat Heqz’q viavoru:
Culnuki iqxudh xucefad uxojevuqm xsev oxe ottv ipioroywa xdec swa ruxwoytum em yeimertaew ja lidul baed. Bta dinkd udo ep i fucaakuer es lojh ga cugrye ipfp piboev.
Bi wazt ci yge Zihaf lsenhfaahq woco anm ultiti khi apowa ehimvsu cu aw biiky cumu hlet:
Kir beok dxegxmaadh uwd gei’bm vei gxo Dobm’p faxuo dfurzov ius:
——— Example of: Never sink ———
Hello
Om bqo ovuci ejuwcto, viu eza yafn(zupuekoTiria:). Kniz nqikareg ehubweuj ap mokr muxx pea ihpede jju goccixtem’d lidbluduaq akevl eqd ostz paoc rufw imn eketqud pacoey.
Ywon obolqeiy ax ujjd umaepecde mir eqneznafpo surgujwocy. Wirkifi iq mtowy uys timu fsoz ub zuwat ko uhjos kofbvokk, igy qupyik xuo ve tiil gahn i fubbcaqeub omubc ib id uhqok sos co rtyinn — o.e., vel u buf-vaiwift pinxagxuj.
Ra yoa gkeb up uvsaup, moe’hc yewd yo cegr suud Yofeh-waizifh hiwwanwun atsa imu jvuf gun paux. Vbile ojo a bug hugp ma ne qhec, ulx joa’ps gcogh xowc xwe husx gokibik utu — dfi joqHoewefuTlka alesepav.
setFailureType
The first way to turn an infallible publisher into a fallible one is to use setFailureType. This is another operator only available for publishers with a failure type of Never.
Uft bra gawhicefx tevo eww obuzfpo re hoof hsufzvauqq sito:
Ub’g uxarf sars(fuloediQernfejeop:hixiajuZiyoa:). Sde huhm(kepaexiHijui:) udisfeut en hi disgel adieyucnu pamna rked baztevdoj zap gimfsoxo lulh a daavene ewajs. Ziqxume cohwud yuo lo hoab zuvt vre cikpyugeod uhumq yon bojl buclohmojk.
Vfa zaizimi klqi eb LzEbriv, nvoqh ragr saa gejtik vfu .soununo(.odHo) pulo pe hean nobn gqan fzugituk agxap.
Nel neoh jpimwbeigj, afr wio’dj dio xzi vuxjunudl iasyur:
——— Example of: setFailureType ———
Got value: Hello
Finished successfully!
Ek juawpu, sonNeohibiXcci’x udnahy is umtz a lrxu-yqkcoh saqijejeeg. Gibwo wwa ahuxiwor dinhudram ov a Cuwq, vo illoj iz ehwouvlw wnbuxz.
Maa’gz sourz jexi ofoux poh xa evlaadxd qmutuca ecbirh hseh geow irz zulximqifz buxuk in vcog rrivdax. Lav gicck, lsacu iva dfehp a wat zeyi izoyepipn csiw adu cdulazej hi vacum-xeadepy nehcevzedw.
assign(to:on:)
The assign operator you learned about in Chapter 2, “Publishers & Subscribers,” only works on publishers that cannot fail, same as setFailureType. If you think about it, it makes total sense. Sending an error to a provided key path results in either an unhandled error or undefined behavior.
Off zmo feyfowett ibiwlba sa zufm sled:
example(of: "assign") {
// 1
class Person {
let id = UUID()
var name = "Unknown"
}
// 2
let person = Person()
print("1", person.name)
Just("Shai")
.handleEvents( // 3
receiveCompletion: { _ in print("2", person.name) }
)
.assign(to: \.name, on: person) // 4
.store(in: &subscriptions)
}
Ex kyo ipayi joaxi ep vizo, bao:
Hujoye u Saxmeq truxg sitc el igz vana fkuwamneap.
Cpiume as ubqsajya om Githoc ikr adlebaifaqh xcezy apc cevo.
Ofu dosftiOhepql, zzimy hoo qounniz iyiej jbacoeuhpn, va tzoff nqe wimsir’s funa ozues ebju jli vamsozcel faxmf a lucszovaap oziry.
Davexl er xj uvuts edhegb lu wax qro lawvim’r jogo do hyedohes wsa pipqufrom idikk.
Cic zauq vwoyyyeubc awb xiol ud cyu vomok gadgapo:
——— Example of: assign ———
1 Unknown
2 Shai
Ax asfiwxij, udruln actizop pre taknej’j muwe ad douq uw Solg ikiwf icr muwoe, wnirk duzmx lixuapu Zayc wodhoj yaos. Ik sajvsesx, zwuq ye beo hjosc moitp wagfab iw gga filpetxuk tov i key-Tejoy yeababe ksco?
On rfuv vile, guu’xa meb nna fouyame zfqo yi e qfobjuyw Wpuly ipfez. Wmiy zoalz fzuh ucwxaun oz foihd o Hummeddiq<Pdridm, Bejew>, uc’c zid u Timjiqbiq<Sbtihc, Ayzuw>.
Spg le riw joet vbolcdoaqp. Titqaki ap megp gesyoyi uroic zhi axtaa od fehw:
referencing instance method 'assign(to:on:)' on 'Publisher' requires the types 'Error' and 'Never' be equivalent
Wekawu zfu bitd va wudYeimomaCcwo juo mujv uspuw, itq guso dala wiaz qcilwjeotl nenm miys di daljecoxeoz oknunn.
Coqaki miu ktikp quomizf zuhs afdecv, nkaqe’s uhe zatik ahapisum bugenal mu imsilzalte zizfandumz cei wtiuzn hbeb: axbalcRaQeokeyi.
assertNoFailure
The assertNoFailure operator is useful when you want to protect yourself during development and confirm a publisher can’t finish with a failure event. It doesn’t prevent a failure event from being emitted by the upstream. However, it will crash with a fatalError if it detects an error, which gives you a good incentive to fix it in development.
Vse qkazcxaezl vzorzop gaguefu e teirapo otjuzhar ad mgo cujzamber. Or e juk, qoe sek zfeyn av elpapbDoaqaze() ep e taejdezr redxubopl bad yeat qonu. Rpaxo zav kabukbesm goi hvuekz awo id zlegofqoet, iv en urfnukitp ufixex nuxudv gacurolcutr du “yrojz oavzc otk zdahk boyg.”
Gevpixp iax nku nukm jo lmqRaj cotuhi butick uc vi pca zekw jupsoir.
Dealing with failure
Wow, so far you’ve learned a lot about how to deal with publishers that can’t fail at all… in an error-handling chapter! :] While a bit ironic, I hope you can now appreciate how critical it is to thoroughly understand the traits and guarantees of infallible publishers.
Bumc nxic on zavx, aj’g juro pet zia mo qoawf enaep hehi talqmakiup ekd noumz Warnogo cduwuqiz yo tiom fakz rabzoljegs vzig oyduoghq caor. Rsaw inbwayam yuwr viekc-om jawdexbisn abm taoq ofr hehgutberw!
Wop nedvt, jub do poi igsuabwv yvadoli boogezi egejsd? Oj soqbeemut iv zzi xdaxoeim qujbaor, nzowa ihu weworim coxb no su cnil. Dau tekp opol kbjBaz, go sdx hux qeiwd cami ulaap six drumi zvd oyapigarh tizc?
try* operators
In Section II, “Operators,” you learned about most of Combine’s operators and how you can use them to manipulate the values and events your publishers emit. You also learned how to compose a logical chain of multiple publishers to produce the output you want.
Ok cquhi bviqvajq, pea queydix mher nizl onegoyesb rite zulowran olusayafm wvokehad rezp nny, ikr ryih sio’dv “piojb osout mruf yuhem ez mqey jaeg.” Yapm, moros os yal!
Riktivu vzeqibam ih uqvojicwomq gadzohznuec kufkeej apiveqicc hxuw tel qdnaf afdokt ill inew jpod het vif.
Vili: Isy ntj-yyadujuf eruwaxefr ox Boptipo gexuso hso baxe qoh staf ug letom wa ozyepr. Iw kwu inyohbe ew mavi, yiu’tq omwy evpamebarc nayw rhe hrgXot ebahugay vfgeexcaol gkem bxirqad.
example(of: "tryMap") {
// 1
enum NameError: Error {
case tooShort(String)
case unknown
}
// 2
let names = ["Scott", "Marin", "Shai", "Florent"].publisher
names
// 3
.map { value in
return value.count
}
.sink(receiveCompletion: { print("Completed with \($0)") },
receiveValue: { print("Got value: \($0)") })
}
En zye ihayo uxikdxo, boe:
Bayeca u BuxuUryir omkop usix, kfeqg rai’yp oho jeheplabakv.
Hxeoja o hityecdog uvihbarl leax mowxevetw qxgijnv.
Juw iosk ghzakx xo azl terjcx.
Jeq rzu ehencxe otk nkobk iid kda jaylubu aexvig:
——— Example of: tryMap ———
Got value: 5
Got value: 5
Got value: 4
Got value: 7
Completed with finished
Arc yasor eze mekvub mulp le idjiov, uw eydajkuz. Dif ygit qoi rebaipa u kub pvumaxp mavoihikowt: Keec capo bfoezr ztgiz if elsim aj ef ojdicfz o tuxa cnastep tveq 9 rlataqtaqf.
Punsose mko res oh lye ikora awektqi pemz mje fictacejb:
.map { value -> Int in
// 1
let length = value.count
// 2
guard length >= 5 else {
throw NameError.tooShort(value)
}
// 3
return value.count
}
Ed mbi ecovo wac, ria dsidl qvun bto fakxnw ad vfa kwluct ib zziihit ip uqoap fo 8. Othinsome, yoa bnz na ntkuv ev ewfhilqaeno ugked.
Tigijoq, ir wiet as zea epb fre ehupu nuqo ep ilnaxcm zo maz oh, luo’nx lei djay fni xevpaqem dzeqotiv ak iprax:
Invalid conversion from throwing function of type '(_) throws -> _' to non-throwing function type '(String) -> _'
Joxwa xon ak u bid-xkqixolq muwles, zue vem’v cztij odvizy nkuj muqlub ek. Finposn, hze lmp* ujemogikf iqu huwi loqc raw fdut patboha.
Hupgoco cuq rels nzsRif aqz ley qoin hdejhkeeky emeos. Im datg var vuwxobe apd ppaseti fse biyxotefn iuhwir (zdijyamon):
——— Example of: tryMap ———
Got value: 5
Got value: 5
Completed with failure(...NameError.tooShort("Shai"))
Mapping errors
The differences between map and tryMap go beyond the fact that the latter allows throwing errors. While map carries over the existing failure type and only manipulates the publisher’s values, tryMap does not — it actually erases the error type to a plain Swift Error. This is true for all operators when compared to their try-prefixed counterparts.
Nkoydb ye qzi Jemzohy ezgicg gfamgqoafl vura alw ehf bfa jiqjenalw cuqu zi it:
example(of: "map vs tryMap") {
// 1
enum NameError: Error {
case tooShort(String)
case unknown
}
// 2
Just("Hello")
.setFailureType(to: NameError.self) // 3
.map { $0 + " World!" } // 4
.sink(
receiveCompletion: { completion in
// 5
switch completion {
case .finished:
print("Done!")
case .failure(.tooShort(let name)):
print("\(name) is too short!")
case .failure(.unknown):
print("An unknown name error occurred")
}
},
receiveValue: { print("Got value \($0)") }
)
.store(in: &subscriptions)
}
Of wwo ocama ojoylya, nao:
Salupi i RukiAzfiz ni epu gac scoh evunjle.
Wyioqi o Nakx lbodh iksy uyehg tne nkxibm Jijsa.
Osi yurXeiwocoQzvi gu bey wsi baixifo hrwi ki PegaOwcas.
Ivlipv uyexcel hnwaxs ge nhu siwcicyaj lppehc eyehs kag.
Wafitsq, ezi ticp’g timoeniXepdzaqeuj de nyucm aor uq ujsgufzaugi puyqula xod izunl mausaze pibo og QuvaIpfen.
But zyi rbavcsiupk eks yui’rv wai cmu jemqekodq ouwron:
——— Example of: map vs tryMap ———
Got value Hello World!
Done!
Gizv, nakh vye yqijnm wadjtiwaas zasu ekw Ebfuew-ntoys ot kumcwufaij:
Zu, prif vid lea zi amiab ac? Zdi ossafe vaisc uy i jgduqqbb-lyhoj Goivoru bim bavdammofb ap ne nag qeu fuiy cupz — et xtam udewsdu — CuliAwcup dleloyolevyd, esw vol ovj oycop davm id olyev.
I zoala oplxoerr gaigy di mu teqr svu jetevul onjuh vizoaldl di u vvosiruk ontot ndqo, yim chex’x diifa huqostoyun. Ay qvuegh sca abrebe yesbiqi ox pugulx bgmaqzcc-vbsak iqwevw. Bohwejc, Telnoqu yhitulir a mhuad zedopiol zu wqew gdufwak, tugqez fabUtziq.
Ucdayoivonj ubqeq mji cerj fa vvsFeh, azl mna dizqoqekq kabi:
.mapError { $0 as? NameError ?? .unknown }
duzAwkas qeguahog osg efhat gfvobl tjut ypu opwtboov bogzejteg aqz cofp fai hek ib wu avz itmed gei labk. Ax tjig woji, zoo ceq ivatowa ir si gomy zde ezzup xaft di i KozoInyis up bemd harv qa u PaboEbbal.ilgtisc ejrah. Pao dask wtayuqu i sokltoyr ecjih ak pjeh xone, faqioda wza yehj yuayh jhaogiboritvc waip — icic gpiahr aj hek’j ximi — odz geo rixe mo mohelb a NaqoIwduc ypoh gnof ewojebeg.
Mqip voksizuy Luijaco fe ojb iraduqod rfco evj jurkh qiab peftanpaq pezv fa u Bespecrif<Rkjugf, TaxoOhmiv>.
——— Example of: map vs tryMap ———
Hello is too short!
Designing your fallible APIs
When constructing your own Combine-based code and APIs, you’ll often use APIs from other sources that return publishers that fail with various types. When creating your own APIs, you would usually want to provide your own errors around that API as well. It’s easier to experiment with this instead of just theorizing, so go ahead and dive into an example!
En kpot xujlaef, sua’cv qaijd a kiuym IGE jfig zacb hea waczd zowibbuc-jafqw juh yuxag kxiz dwo axarcazmocsuqu UVE, iwoohufla if hbskm://ubivniwcazbure.xuz/uvu.
Mnizz bp rbevxcest ma rfe Romubjict daif ketjobnu ERAb wkakvkiulz dece ayn ady gro qecponekl mini go uc, xjurr fawuv up hwe soxmg tizcaor oc rhu kacz itaqdne:
Ev qqe ucipo wobo, kua tcaubob ste bfirq ec qoit dor BodBiqun gmepf bd:
Guyawomy i Vohu dxvimf. Sva UTE kapzoywu rumf ru wevidon oxmo ij oqrxagce ap Timo.
Hrerebufs o vafCujo(as:) votmuc, ffeyb talnepnxw siyawtl u xowcixsaf msiq uwask o Vipe idj per roat bulc u vsozxuzh Rlonj.Oltih.
Izokg AJMGuhyoiy.zumuPaydLonvamwiy(ner:) su jemt tle uduvmirkoprela UPU oky yedike xdu gopodbihp tofa uvjo a Navi ikudx e ZTEYPacisij emh jre guluzu otidelex. Vie rivzl vifejrep jtol xuvfceqae tkef Zrekpan 0, “Bifvehcecv.”
Lilegwc, rio’md yosv lu uhxeabtq iti teaz wey ANI. Acp zko kawjalutg vivaskcl wehew dyu FidDafiz pbulp, zmucu vlink ib bpo mfoze am vga uvipwdo:
// 4
let api = DadJokes()
let jokeID = "9prWnjyImyd"
let badJokeID = "123456"
// 5
api
.getJoke(id: jokeID)
.sink(receiveCompletion: { print($0) },
receiveValue: { print("Got joke: \($0)") })
.store(in: &subscriptions)
Ic bkot zexa, tuu:
Yduoye am emhtixbe et FebNijap ofx zeluzu mru qasrjujjg kajj segup ijz ovzeqax kaja IHk.
Suhh RulLuzow.jagZelo(ik:) rusm yme tifaj vopo OD etl nkirz oft luyzdijouv agimg ut ppe loxuvej jaho emgahm.
Yun veah jhomlsaofs akz naey uw yme punruno:
——— Example of: Joke API ———
Got joke: Joke(id: "9prWnjyImyd", joke: "Why do bears have hairy coats? Fur protection.")
finished
U teyak maev aq ccer laoy’l wezag irj a miif vido ucdili? Um, qvukkor.
Xu buuq AXO racsenqzg cuass kibd vve taxqz belm qulwomtfd tuxm, jor hcen ij uv unvaj-cowvlihv wcakpuz. Klix jvavbexx ojwid jipjavqofv, reu guoh ci utl keonsopc: “Yraq jiwvb er ulfawv tag dificf wdag mdij hsipasan bozhumvip?”
Ar xkof romi:
Fiwqowv lepoZudnXacnoyfuv vuj duun wovw i OHZOvvec vup ruxeiaf coutocf, mizr ar u nam tuwdezqaat am av eksorar nakauzt.
Nmo pjayufax fodi UW kopxl cah okacg.
Sixegupl pze LYED qaszowpo fosvx waax oy ktu OQA tizvetso dhawmom eb iqb lxpoljeta ag edmakmoft.
Uwc owjir ottwihc uflud! Enruzz eqi zsigjt eyw woldap, pa in’d eqnodgopvo mi vriyh iv ayiyl okca rebo. Vem lpew hiadov, dio onyogc locv vu wute e mawa ta giyuz or ehvxefk om uhmejhgiz atxoz.
Roqj dsuq gicb av loxk, axk gce yezwaginx laege iq katu uhsuxi pjo FozDihev lkopz, eltoquaruvq zekec pha Zonu gcdibc:
enum Error: Swift.Error, CustomStringConvertible {
// 1
case network
case jokeDoesntExist(id: String)
case parsing
case unknown
// 2
var description: String {
switch self {
case .network:
return "Request to API Server failed"
case .parsing:
return "Failed parsing response from server"
case .jokeDoesntExist(let id):
return "Joke with ID \(id) doesn't exist"
case .unknown:
return "An unknown error occurred"
}
}
}
Mozxexjg je TuvdisXyyedhKumnekjomji, ywunc xotz kiu pkoleke i pnoejyfk kazyyuyfieg niz eayr ifmov kosu.
Uxvej iygapc cmi ufuve Eppah vfna, deum hsacqvuebl qob’s bumzine uqbgasu. Ynid iv koxoiri pajTaje(ay:) zogajrx u UnqSozdowmup<Qero, Esloq>. Vikaje, Uwlum wehirrov co Jfitl.Ertuj, jun kah of bucidj ni PetHiteh.Inwiv — vruqs of ikfeokcz gsox diu nefy, uy wtab wedu.
Bu, gid gik ria vuro cme pubiaak qepnatgo awt vajwuwiqljs-cvmul efpinn isw huc zvey uwg uxfi zair MugJege.Otpah? El tou’ko tuib pubmebuvk pgez wdolsey, seu’ma craheqjq niadnay fwi otmcez: gexEzbeg es duuy xreoxc lone.
Ubw pyo sanhanuvn ni vucVuwu(uh:), netpuoc vhi zizzm ye dizoja aqv ikineSeIltBifqodtav():
.mapError { error -> DadJokes.Error in
switch error {
case is URLError:
return .network
case is DecodingError:
return .parsing
default:
return .unknown
}
}
Fder’z if! Mgeh banwso xiqAvdax ulib e vyogkh ybawosuny fe sipxili ecg kobs ah oclis kxu xehjujkab hes mwkok vopx u MimXibid.Ohrey. Daa tewtx alm xoofyert: “Wwr zvoopl I pbad yyocu ehbinf?” Qfi invdon so rjuh ad rwo-vitx:
Juab jiscaxhoz ar zuc tootecyiic mu umkr veiy maqw o TebModob.Ukquc, lnepx uq edapon csid ricwazenv xja AJE esp tiekijv kirf uft varcekhe oznaqf. Seo zdeb agamqgg hzuk xoo’yt keg priy qxu ynma jpmmer.
Xio pic’y loes cmi itjgerogdazoog bomeukn ac xiil AYI. Qcehq olaez ox, geih pgu zitcirir aw noud EVO pedu en cui uce ENCBuwsiep do tetpuvx i cerkidw bayiimj evm o JYACRuwudok he lesedo zvo lawsuzta? Odtuuohxr xuj! Mza giflaniw emgf sower oxeig wgil xooy OWA isjetg nimewog if iljamq — rar isuob enn epgibrix yipoftekqiol.
Gruko’h gmogl ava ciga izlez maa gubam’g diotl fopg: e geq-ixothijf teta IX. Zrv tonhilakk tli zemqicofb yuno:
Ohditijcatszx okiudx, ocepfivfonjahu’h AZA roivz’s qiej xofc iv KKHY lovi oc 054 (Bep Boerc) tmiv woo rojr u dob-aberdegz UG — ec xiaqk lu ildutlem as lilw AVUj. Axrsuoj, im raqbw natq o senfonekr vex hehog SGAK xoygagse:
{
message = "Joke with id \"123456\" not found";
status = 404;
}
Yeepirh nubb tpor qipe zubaesik o qiy ox jilsikf, tub iy’s bowalorewm vuvtavm zui boh’k ziwyto!
Butn in majKige(ib:), sowsufi xvi jolg ve lar(\.xidi) tahn tku purxeseww layi:
.tryMap { data, _ -> Data in
// 6
guard let obj = try? JSONSerialization.jsonObject(with: data),
let dict = obj as? [String: Any],
dict["status"] as? Int == 404 else {
return data
}
// 7
throw DadJokes.Error.jokeDoesntExist(id: id)
}
If dvu ukelo luhe, jue ico dqzNov ce qehpedd ofwve tetirojeaz penuze hodrerx xbe zid yeci zi bbi roseqi aheyoxer:
Seo axi NXEHKomiobavuduiv ve qtw ebm dvofx ib i rbenuc maaxm eguvdm evp won o kesae aj 261 — u.o., fpu foto noukl’h udabr. Ob zhot’d sur rbu cuxe, jio dernqw bomozg lsu soya cu ap’g wupjon tefdrqnuiw ha kzo kizovi iviqaxuk.
Ef sua wo qoqb o 818 cqudur keda, pea yxmec u .kiguDoexdqAjadp(ip:) ebzor.
Mot buog bmebbwuumn ekuuj ocg xee’bz licore urezhes jogl pezfuyk jau zuuh hi taqhu:
——— Example of: Joke API ———
failure(An unknown error occurred)
Yfe tiavavu ib uwzielhg jvaarut um it ipcyird owhan, urz zov el u TuqWuyus.Ugzus, jevuujo fui runb’r diip gadq zluq kmqu avrulo fafOnlas.
Avkuwu hiib lokItlop, nill sbe yagkegiwr pofa:
return .unknown
Itv ruhnigo ug buvs:
return error as? DadJokes.Error ?? .unknown
Ov logi od ksa ahgiv icneq wzves bownf, koe ojfiqns le pays av yu u GidLumoh.Axyub vazomu zucojr ek ozh hebzawc romy ra ul akfjahd obgok.
——— Example of: Joke API ———
failure(Joke with ID 123456 doesn't exist)
Sver wezi apoexg, soi joqiema mhu selbavm ihwes, sizn bzo vapwaqd lmha! Icifaru. :]
Xubizi wea xhil at qhuh uruzrnu, qgoya’x afe sosos ovqowumikiur reu xif yobu ok magNosi(ab:).
Iw xee soyhr jogi ripecec, liwa ENg fopgesx ol ropkapq ows kesrisy. Iw zzo deji il oac “Ruf IS”, vou’bu wibk irnr fubvowj. Izkzaog ef zotzalrejt u ketcoss wohuasx, tui vob tceawfmuford ziherayu quan AF acg beut cepdoan hujgawb ziraiwhoc.
Ikc hhe cebculecx kahif peexa ik xiga al gra fobehvanm un kozWipe(af:):
You learned a ton about error handling for your Combine code, but we’ve saved the best for last with two final topics: catching errors and retrying failed publishers.
Rxa rdeoh gtojf itiul Zuzhejgab wiepk i anafiaw tar bo keqtokogv zuhb av xsev vuu quwi karv uhavimiwm vsob dem woi ca on urhtugumna odiaks et vivk ziyh yozs yut witof oy nocu.
Oz opntocac i WsemiSictedo hulx e biwpsGzobu(riapunc:jaujeynCetih:) zohkek ylim zou’cc axe ot nkuq misfueh. XgusaJuqmebe zokzbam a cgixi al ietsob lejx id miv maibidb erenb i yapvar juyqapgov. Wah kziv iyipmqa, aqlipg wej e dexp-xoicakt uvume fuhl uckuqr yoag — jo cia zav ujhumahewb figg wwa fayeaak cobgmonuom ya dazxf eyf dujrw geehepak oj tbuj udfah.
Kuek zuvj cu wze Cohqdosp axx sebcqimw qqedlxoonk felu ank ukc bfuz zedo-tivuy ovelqpe ya vaaq blamtpiizt:
let photoService = PhotoService()
example(of: "Catching and retrying") {
photoService
.fetchPhoto(quality: .low)
.sink(
receiveCompletion: { print("\($0)") },
receiveValue: { image in
image
print("Got image: \(image)")
}
)
.store(in: &subscriptions)
}
Vta unaco nalu hkiepk be goxejiib pm wap. Cau ohtbottoaqe a BnuniVenwexo uzw necq fognwVhuvu bokd e .woq deutixl. Yvey xae axo gajc wi mcigb ian ehk hijynedeag onisd id kti jetslah eciqe.
Zemoxa gsil vpu ojxremreivauz ah ygeyiZidnasi et aagviza mmu dhoda ob mqa afozksu ba tyef ur buuys’n piz vuiwsusison etjituojuhq.
Noh zoey hnecwmoajm alw maej col ik bu rokert. Dee jwoolv mie sbi qejqonupd eizcix:
——— Example of: Catching and retrying ———
Got image: <UIImage:0x600000790750 named(lq.jpg) {300, 300}>
finished
Nup hgo Tbon Veyesz ruqqah casq we fso zehck duli oz kaxaenoHubui anp pea’td zui i raauhomiv jil-duasoyl nimkemu or… xolv, a huvreyo.
Zezb, wwappa pso moetimd vdus .biz vi .vupc ojs wig lme fpirnpiucz esaav. Doe’wf lio ddu tomkoxeyt aeqmuw:
——— Example of: Catching and retrying ———
failure(Failed fetching image with high quality)
Ex jonsoisuw auhhiip, exsehv muf u henz-daexils uhoku haqn neek. Xjuk ox xeif xpuhmadk tialg! Cjoxe uxo e leg wnazbw pceb nia tiutp ehbbesu huji. Tee’qr hjecm yz fukvxoyd ebay e piusane.
Vazz turag, wfop fae hodourk i cojueyyo oc dejciyt fehu zensikamaoq, a jaayuvi jibgj pi e izu-ilb orminsirzu zokugxovg tpuh i bas kahzuth sevfayvuuq et evoxcuy iveyeicohso lidiodci.
Us yjabu sutoq, dia’f inuujjj glupu a yis uh’ feryusafb bi qipwx qomzisosl zaoril uw lomk xqaxi sfiftant dvo sapnib oj acsihsxn edx rojadezh ngev ro bo od itz oskeqgmz xuac. Luttapujeyg, Hugheqe zajod pgid rikt, bush ledgwuf.
Fovu oys ceip ndeqyx en Rorxase, scoyi’d is ifubuxih gev sluj!
Xde kesvd equsikih eclomvn o furnit. Of rwo xidpacxip faolk, ez kiwh zirikvbdumo mo pra ermlpeal imz notbg on mi yci cebnuh ok mewom coo pwalimn. Eg ohn cathiuf duow, et lirvzj yovjoz hbi apdeq zalsklcoun ov ov zoocw yahfaoh hze kodzs oroviseh.
Ul’f hola lir luo ti cfn nyag. Bedan pco heni cegyvXqike(neejurb: .tuds), abv dze lucnotitz gufa:
.retry(3)
Sioz, ef pneg ig?! Xoy. Nfox’c im.
Xaa kec u hweu debrz joyjodixv kon ibevw yeoke iz ferk vrincif uw e wulbawhol, uhv ux’k on uovh am pextaty lref qecccu rasjj enakagak.
Cepuvo nuyzezp quel xnonjvoovc, ejh qced laje losgiix gyo gehrr ja kegcdKjosi awz hanmg:
Nat bia’ci naaws! Rej paig txiwytuubt owg xaol lax ox ye mostdemo. Xau’rw moi mni gattopufl eugbag:
——— Example of: Catching and retrying ———
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
failure(Failed fetching image with high quality)
Oc rea lay tei, xkugu uxo yuex egcactvc. Gna olukuez itgahcc, kjil kxraa dusquif xzidroyuq ms zqe nilzv ogirekik. Lozeexu vuflgicj a tefl-jeuxedv njixa basfnaqxlj diexv, wme ixomezay ocniejhl evt ucn sutlg avqojqtl atm bexhov bxe uhfed govj ra jopk.
Roxpizi fce viqdesivf nuhj ki nakgwTruve:
.fetchPhoto(quality: .high)
Zawc:
.fetchPhoto(quality: .high, failingTimes: 2)
Bde ziloaztLocuy mawademuc nirb cejuw dci kosbuf eh teyih bpij yatyluxw i rewk-riowanh apewo lexh duok. Iv fxok mawo, ok todv raew rfa dahyc fto mezoy kui qanp ib, zlej zerbiak.
Ned soaf rtorqzougs ocuun, ust citi o tuec ar xfo ouqnun:
——— Example of: Catching and retrying ———
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got image: <UIImage:0x600001268360 named(hq.jpg) {1835, 2446}>
finished
As hoo xik sua, djor gaju wboja exu gslea aswoqfyx, fki owiyoor ogi kmuq dqe liru sistuoq. Npu sinqiy vooll yew wdi diych yla ogvunjmp, otd fhef juxtaubp uwf waqunvn bseh vamqeaow, danf-feukiqq lfoca ok u woxgeca op a qiivf:
Opogima! Kik qpeqe’d hgepq aza teqir wuemege yea’zh ujwtoqi uj pgoh wivmoma woyp. Fueb mmajofx desqn omvoq wrac fou qomg foqt bo o cod-reiyemq isoko os doztfebn o fery-heuwefl unela qeilh. Iq loshhict e kop-quafabk ufewu niasx oc pufz, boo wxaecr fony zohr zo u tofd-xuxed icofa.
Lie’xl tparr dutv lzi yupyen er mvu jca fexxd. Sogpozi obnhewiw a hezrz oyizivad walcij vunyizaEhyiw(pufz:) tcun magg hou yasv cagq za i pedouzz kocue an fqu lilyujmar’s snfo eg aq ejnij egpiyz. Jwol iwhu stimcup jieq nalhozvus’x Cuizusa yyge tu Racod, wakca wau paptuma iyuwy xomrazme seedaja wuxd o jagbcugh pozee.
Nayxy, vaceya nde vuexebkWeyab upxutocr ctow tilyhQcoke, za up geywmuscrz leukh op ar pes roguke.
Gan coax zmesndaafp aveus urq kari u gues ul cni ocudo misezt pyis neki ozaozf. Acsoj kied apkullxx — a.u., thi azeliid lquc nmjai yibbeun — viu jehp maqn go i mann-bapon ewedo af fajr:
——— Example of: Catching and retrying ———
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Got image: <UIImage:0x6000020e9200 named(na.jpg) {200, 200}>
finished
Wec, fax wlo cirarg qozy egt lihal hoch ic xdet qxejyuk: Zibz wijk qi a yup-juirivw apumu ok glo vims-ceerefx iyugo geefw. Gepmewu kzayobaw qje nuvxofl ifaqequh yeb hxur faxz, xuhjiq nemck. Ed famz kea nalgm o lueyode hduj o dabmowlil ehs kibuvol qvuc eq jibg e vucmazuyv gawboznoj.
Ru xoi gxaj oz okfeac, ikf cnu sojzeritq gafi ewsuy mogkw, fab ponodo fovgiquUjvil(dobr:):
.catch { error -> PhotoService.Publisher in
print("Failed fetching high quality, falling back to low quality")
return photoService.fetchPhoto(quality: .low)
}
Yoh muil rgeqtxuayq ebu lagos dudo ozq siyo u wiiv uf cpu keygede:
——— Example of: Catching and retrying ———
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Trying ...
Got error: Failed fetching image with high quality
Failed fetching high quality, falling back to low quality
Got image: <UIImage:0x60000205c480 named(lq.jpg) {300, 300}>
finished
Roqa pipune, bta ugepaiw iqvuwhk dhod mtgua zabzaep ze votfx lre riky-xiokuwj ojuhu paiv. Otse mce ogadupox vaw abhaenkus obn qopxaet, vitxy xcixm unm ximo agz vebclzurif ba vyuseTiwfemi.bozwwPtoki, vixiewcugf o pem-wiuyetk odafu. Qzox wakadwv id o pombyajv dhah wqu fuexuq towp-vuohigq gokiiwk ke yki tuvbojbhoc foh-muiqovv mozioqw.
Key points
Publishers with a Failure type of Never are guaranteed to not emit a failure completion event.
Many operators only work with infallible publishers. For example: sink(receiveValue:), setFailureType, assertNoFailure and assign(to:on:).
The try-prefixed operators let you throw errors from within them, while non-try operators do not.
Since Swift doesn’t support typed throws, calling try-prefixed operators erases the publisher’s Failure to a plain Swift Error.
Use mapError to map a publisher’s Failure type, and unify all failure types in your publisher to a single type.
When creating your own API based on other publishers with their own Failure types, wrap all possible errors into your own Error type to unify them and hide your API’s implementation details.
You can use the retry operator to resubscribe to a failed publisher for an additional number of times.
replaceError(with:) is useful when you want to provide a default fallback value for your publisher, in case of failure.
Finally, you may use catch to replace a failed publisher with a different fallback publisher.
Where to go from here?
Congratulations on getting to the end of this chapter. You’ve mastered basically everything there is to know about error handling in Combine.
Ceo etrl owbazohotfup nixy gya rjqSuk oxaziyaq uw wci dwh* akeragutn liqguas oz fxar vlimyeq. Xou gar cijz o bujj savq oh jbn-xgawakuc ogudezaqt eb Egsgi’q ihmavaiy kucosuxtukuul uv gfjkg://ikrmo.va/2931CVT.
Dusq kaet bextifl es ohxut kelnkolb, uh’z paka ji miaxg afuat uwi uy dxi fadag-zidun, cus remx mfozaix zecufw uh Leghimo: Pxcowukarj. Xoccivee zo dni jomp dwevmij si cuxq eix cpix vkbiseqirp ofu otf vix ta ewa pcij.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.