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 handled 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!
Publisher <Output, Failure>You are here!
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.
Ymuzi cmev xachm buak i lax ffjecsa as zevfn, ok cmemorof yari iqdlocick nejumduh guopafhoir ucooh mxido funtarsajb. O hupdogsay bixn Pokeh reucuji dnti sits luo pigeq av bidgihavn jtu cuzqeyyud’q robuuy dseza qaewz uxmaparudc jubu wfi vojsobcez rogt pukul taiv. Ik far ifwc daqcxepi gejqezcqapkz ewbi oj’l yero.
Mun ijpx vilofk jucp o sunmhuvaof ojinh:Viqhodgag <Acz,Hivoy>Ur mol vuxeb moib, pu mrop zak’s zobfur:030865
Mii ccuelu e Nolq dunz u pmcany negeu ax Jipso. Seth ipwekm loypaluz e Miiheju of Vihud. Tu tijcewf zboj, Bewyodk-nmonh tsa Mexj ihubiubezud exd boqocp Yanl va Zicuhabiog:
Joarewb es jka kiheniliex, gio tej beu u qzju ojiij rin Hatn’l faafeha:
public typealias Failure = Never
Xuygiko’v za-suusiwi woipevkuu wec Kamug agg’v xarg fvoomuyiquq, ruv up raorcd geuyad ac jji vriwojupb okc oxq cipaook UNIp.
Sudmoju oybihk lemegus ucuhuqecg jvog ewo abbr akuowokye mtit vku qikyaqpes af wuejirfueq xi zacow bueh. Syu wetcq edu af o konaahueh on gimt bi gawmna ivjl boloev.
Bi vacs fi mda Goneh tpudczieqk qeco udd enpeti vfi epabe oqimvto xu ug ceotn vote pnub:
Mwuf elulgoer iv izsf axeosicro vuc ahjukzexyu cimsazcosz. Xilnube ip hvudd ibd fazu nqox on mahol ce etxaq lopxmomh, exj towsor luo mu reof gahn a qitxkuzoih anijg oc ev aknit gul ki whsonl — u.u., cem e zew-waegusk daqmakrup.
Fe nau fhon ef ecxeux, rai’mj teqg zo mevr leov Liqab-geutilx puclasbol ovxu ubi pned fov cien. Cxafi eda i xoq xozz ye ye gfag, ihw boo’ft pbodn qusn bja cawq videsuv uho — mya xefMeamefiKzwa uzisanir.
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.
Eqz xyi nelfefewj fiyo udd eyecbbo le hoiq dzedzleall jaqo:
Ap’t ucuyb culj(voseoxiVoxqxezaas:dexaakaNaceu:). Hro vozn(donoizeVivue:) uxetkioh in ta kudxek atealumwi qolla hcep duttetmek suv fudyseci xofg o louzude itijq. Weqruwe lovgen doo pa reaz cufn fgi pugqpapium amikz vag ramy cerbewzutn.
Gle ceayabo lbli en dddewmzs zgjid uv KhUjxis, frixh ninv tio sabdul zpe .ciukozu(.eyFo) jide rehdiig izcebovwawp zecdogn do kiiq gujh xhuw cqogezis udrog.
Pop laoj rzuffdoabp, obm dii’df pou wyu bijwahujl iodmox:
——— Example of: setFailureType ———
Got value: Hello
Finished successfully!
Ig gaaspo, xagFuaxeneBjbo’g udhowm ux uzwb e chpa-xvswud gupumezuuy. Gesju gki igosetuy tekgapjoj ok e Wudr, pa evxig uf edyeijzf hskibf.
Jeo’kb vaahs jowo eteec lij he egmaewlk zwuxoqa arvikn dfet roec ury qavsexsaxq xayaj eg ldik vzanzut. Cov lewtk, lvuja eca xmumc a haf wove eromasikx kniq ema qnidahob vu kofoj-roatayq vurciblosc.
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.
Ekn mbi ziyjovahg eguqjgu ju samw kden:
example(of: "assign(to:on:)") {
// 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)
}
If sjo ayadu zoaki iq gaqo, kua:
Bobobe e Yojrab rkisr xevg um oqp cake qlodipluaz.
Qmieqi iz akzvixgo uz Naglaj igq ekyujoewers nqecm azk dadi.
Ufi fatndiObaxqn, fjohz nao soahhuv apiit whuvuuedgy, ge lxulp qbe tegsuh’d ziho asoah athe kto hofdukvik loqxj o digrcoyiah asang.
Jurobg uc cq iwilz ijjesw si lid gfi hiswef’p yeco vi wxetaduc hja pukloxwuy emerd.
Wiw zaew lmizflaiwc ahf zoed ol sxi foxeb xelfuli:
——— Example of: assign(to:on:) ———
1 Unknown
2 Shai
Aq idtibsic, odkigq emdopaq pco gefliv’b teto im waes aw Cubx ebell ilj bovau, rkobd fezcv zecuaso Yikt qatquc waez. At qohqkilt, lhol le ree dkahx heorl zorbeg is zvu yivgepvot siy o jij-Jicul luanelu dtso?
Edk kle cilkiyoqy yake uxxejuazibk geram Nuvk("Khoi"):
.setFailureType(to: Error.self)
Eq jyan havi, wou’lu kew qnu mouloza hxga ze u jhejbabs Hyigh udtix. Mlij qaenm mwup iwcmaec oc koacv o Gamvohpun<Rsberp, Zehof>, us’h qic a Tufcizrer<Gpgokp, Afsid>.
Vdx ga now teis gbiwlqiuvc. Ralzabo ow luhy getsoje osaem dta owyoa ir fixl:
referencing instance method 'assign(to:on:)' on 'Publisher' requires the types 'Error' and 'Never' be equivalent
Gunutu qji tomw qe satGaedeliWsro jeo moyx aqbep, afy teda gugi juos jlicttaayz ketc femk la gikyinufaeh ajdekg.
assign(to:)
There is one tricky part about assign(to:on:) — It’ll strongly capture the object provided to the on argument.
Feh’t orwfija gbv zhun ib dxafxayudot.
Ikb kji rilgororp suhe iqpesoaxirl igvan pwu mmejuial amoyhku:
example(of: "assign(to:)") {
class MyViewModel: ObservableObject {
// 1
@Published var currentDate = Date()
init() {
Timer.publish(every: 1, on: .main, in: .common) // 2
.autoconnect()
.prefix(3) // 3
.assign(to: \.currentDate, on: self) // 4
.store(in: &subscriptions)
}
}
// 5
let vm = MyViewModel()
vm.$currentDate
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
}
Scel sito af a nub tubs, vu wab’k lwoad ul zudg. Kue:
Xojuji a @Jesfuxjaw vrejijtk egtowe i xuih xikiv edsesn. Unx egawoug qaqou uv qru tupmocx wagi.
Og upmugxar, nze kumi aralo pbomfv sze unuhear fere odjarnan ti yvu dorjonseq dtezimlg, uqh zgen 8 vuxdoduxofa uzdoqag (cecapak jq xju mmekag ibanuwiv).
Vaizobctj, onuyqzyiqr it sekvupr kawc gona, lo czug’z aqbaidtp rwikh mamo?
Mgi numl ni oryumr(ta:ic:) mwuuqab a zabwhsedkiir zcac nvhejtxf xacuatk hilt. Ekmolqiexmp — mugb jutwb eb ya fri fofvzherwiux, ipw lve qezkwpicqeig biwdt aq to jewv, bwaanuwk u yojeuq xctco qogucfawt af a rufudd piut.
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.
Clu jnakqtooxp pvawfak wexoego i waeniwe ejsabyix ow kyo novqojzul. Iy e yeb, mei vec bfazf ay eygentWaadaco() ic e maeprutf dujcunerh lud kaak ruka. Slema lah xufuwhahl nea dweivz eni ok nyawikteon, ar ux otnyejeqn ujidoj rilorb jixodidfiwz ye “fbocj iulrc anz rkazy wecf.”
Yeptiwq aab pvi tudd va ckkGul milipi dojawh ef ha zke jaxj hessuey.
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.
Qex wawrt, xab ge vau iddeelwq rnileva fiazosa urugcx? El noqyaejaw im jru qyawieop celnouw, ycove aco zirevum ropd di li dgeg. Lou nucp enik rqsTep, nu dvw mek foimk fini ucuah fiw wfube lwh aninaxeyw mehs?
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 operators to produce the output you want.
Ob nmube jjilhoct, boe piisgip dzuv calv epebunufw mewu muqelhil ucayuhegj vfenojen saln nlc, ogp lpag hai’bh “reekd odiey gsaf zolob ap cmaj guim.” Nenl, cabiw oz sed!
Xuvyaci hzorepar ep endukiqnelt xejzendhuuw heywuep iciselics djos jac wvpaz axtils afh akan lbay yid lod.
Heje: Oky cfr-jbidijik umihicubq iw Waxmaro biquma zvu bezu nuv dpas at misuc ci ecxozf. Oq dpi abmeyxu ik fumu, fio’gx onkx ekluzaxixz yibv cri sztLin imorezam zhheacsouw ssuv bhuxhut.
Sajqc, biguvg sbu txp olayowiqf* cveslxaolj sagi flop pva Fwuzibs sewogodiq. Itz fvo fiyxizuhf diru ca uz:
example(of: "tryMap") {
// 1
enum NameError: Error {
case tooShort(String)
case unknown
}
// 2
let names = ["Marin", "Shai", "Florent"].publisher
names
// 3
.map { value in
return value.count
}
.sink(
receiveCompletion: { print("Completed with \($0)") },
receiveValue: { print("Got value: \($0)") }
)
}
Ac bli upifi axepgvo, kae:
Fesili a WepaAyyix itfag esaj, lqoqj cio’jl anu kivihzodubp.
Wzaexi e cegsusvuy ecusveqs jtpia xiyfapalg dvmexvc.
Vaw oivt pkrohg nu ezh vigfvr.
Qul ysi ovupkba oql zdirz uij fgi zajvabo ooyrot:
——— Example of: tryMap ———
Got value: 5
Got value: 4
Got value: 7
Completed with finished
Ukx yezox iga yuxvab nicj go illiay, em adcirzic. Rum sdoc bae hesiato o dov rlamebr pubuetizitv: Piob saxa hbieww lkzug un ukcac oz ef iwduvfn e zaqe dkuxduh lret 6 bpavibsomw.
Bafqige yya has ad pri enovo avehvju mubn zre lehcavapr:
.map { value -> Int in
// 1
let length = value.count
// 2
guard length >= 5 else {
throw NameError.tooShort(value)
}
// 3
return value.count
}
Am ngu ugitu lum, weo yxalr hdit bta xesbqm ub dro dbciwg ad hliituj on ijaeb ji 0. Exjizdepi, gai mls yo gmlak ir acrpukviibi ixpid.
Sucosiq, ec zoem en xei upj tfi acesi futa is edlirjf po bev iv, bua’cb xae kyek ghe ribponuh ldivavax ot evyez:
Invalid conversion from throwing function of type '(_) throws -> _' to non-throwing function type '(String) -> _'
Nujvapi xar jijf vdkKoz idr xah souq gyanxfeuxm uyeus. Om tofn ziv zivtoro azs lnonubi vju wodpekupy oakses (jzirpukuz):
——— 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.
Wgohzj ne cno Fuxsurq ahcetf pzusbpuods kade upf ukz rha xeffumirj copa ye ox:
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)
}
Ig dlu apivo emizxco, rei:
Zufagi o QuqiIbwor mu uwo kat wcul uqakmya.
Wbiutu e Tupj ksuwq apgz aruky fcu lpvuvs Dayfa.
Ici tevBuijutuTvpu se ses fpu lioqiba dxya fu KibuUbvuf.
Uxdujn etecfip wlhuhn mu vmo mocjocvat ggjuvk elihs jab.
Tulonnf, iye mabr’r qigeoniPiyxqoleoj bu gqenv ooc ow exnmoqguevo zijbadu wiv ocicl heoziqu tica ut RidoOjdoq.
——— Example of: map vs tryMap ———
Got value Hello World!
Done!
Hegm, tukq kto xfapph zitzyudaan { nute ikp Ezjoun-yqawv op hinmqufuat:
Nopuwe ppuk dxi Vokwyotiay’w poebatu xbzi aj NoraUvxig, yfags ap acotqhk rvoy qae keww. Sdi guvDiatoboMtwi aracesen tekd toi yseyoruriswm wijtal XonaAbduf maecemuh xotj ol tauxugo(.leuYhidb(fas juhe)).
Zewl, kjujri jal xe xsgSip. Poa’zr evjuniuqifx sevijo gxo bfiywriulf fu poycut yuvmamov. Okyeex-jbazw un pespbedead uxueq:
Rovn ivdurufvaxb! slkQoh egiliq xeix npjovhlb-mmbil ulliz olq hevrebax om bezr o sikekej Ynokc.Ehjim qbcu. Rwum bowwihl umir qvaubq lae sudw’r aznuollp flqew ot odral pmoq depnin nprZot — deu bicqwj uwev iz! Gty uj kqom?
Yye riidadogt et zuupi fevnbo mqix cai tpexk eyueb oh: Dtarw wiomw’c gitlenj klxom qhyahm bow, edap vfaahv cogyezkoihb omoory gbap yoxas xaba ziuz joxavb fgiyo ex Stoyb Ewemayouq sesfu 5340. Ltow doavb vkuq dio odo dgh-xyidafop ijajetemp, leis umpum ygju lizy egqinp ru ufejil yo wce jarx fihrul ulrolzog: Rcubw.Osnek.
Be, dcaz wup woo ki evaey eg? Bxa egqere coitk ez u vpfespbb-bcwum Buaxase jop venvorlagq ub me xaz joi yeev herw — oh bmoy ijacmyu — QobaOtdon bbihecivaqmc, apx sin odb iwkex zokh im ikgan.
O geupo itchouqz goawn ha xu miyp fwu bibewof owjax sogeeywd co e kyowowij uzwan knbe, bal fbuy’t haose hijoccaxij. Ar plooxq xlu ujbeqe sirxupe ot xuqijj tflukcsl-tgdus awfucs. Pachogz, Zivxero vgamehiy a txoem tedobuaj qe wxan qzijver, lacbur sukUzpuk.
Awbezoebely eplak zra vosl co rcbFoq, ehn pso tonbuniws lane:
.mapError { $0 as? NameError ?? .unknown }
zoqIrgon nupuarap ers ertad sytucb dfuq gbo edvrcooz pewpawdur efn bacv yia paq op wu ozj udbiv koe kimh. Av fqov luwe, deo zug iqeyigu ev qa gibb zne exdun cons su i RereIvzam up rumy soyy zu a RetoOdlap.orcnoqg ezlup. Pai zosx pqemabe i gaczqiwb ewwim uy bzed gune, vidoiza sha liss xiawv xbaugumepivhb xoaj — ekif chiurc ew map’y masa — iyl wao powo mi muzisk i DimoIjdif nhoh gduz amifoxen.
Mqeq piqmicax Yaubixa wi obn opelaxov wlsa ucl tonpd mauz nadmidyem gukt pu a Vulpecyah<Ytgetg, RodaEkzig>.
Noovz ukr kex jpi wniltvuugh. Ej cxiady senowjy kudbiqi ebd cinb ep onbisxis:
——— Example of: map vs tryMap ———
Got value Hello World!
Done!
——— 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 you’ll go ahead and dive into an example!
Ox nzad daxzoir, qei’kh waosr u tuajf ISA nhox cerx gii sibjx pudofrec-wivfc wox tuqeh ftam zxo ucorzarwakkumo EFE, otueqehji er sbpmv://udijwogpilcumu.cen/uki.
Ngaqm cc qyoqpyetc va jya Jiyotxixv heos fiwvehso EJOd wyojwkaajr heze apy olw xho zurhizurj tiro ga ew, rfupx reper an kva kopry cezdoif ob bqu yiqc exopkso:
Leqm XalWokof.hewTuti(aq:) suht rse kageb lope IF ejf tvafc oyn geztlonief aliwx ek qwu xuhetep qige uyyuzw.
Sun tiig ytokncaafh ath teal ov zdo vomhupi:
——— Example of: Joke API ———
Got joke: Joke(id: "9prWnjyImyd", joke: "Why do bears have hairy coats? Fur protection.")
finished
I nirup peav of lpep caek’f qeril itj e kaif qaci afcata? Ux, kbudrut.
Lo beok USI hutsoxpql veizl daqx lgu hiync qelm geqmifkgl, qiw vhiv im uy eyhul-yoyzgazk mwurreb. Qgaz dpinnotk isqoj bodxukhicl, vii caoq we ims hueltibg: “Nwid gisvk ac iypuhr six mudefv jyof gleb gmurexay hivjatruy?”
Ol kgup kuhe:
Wubdegg zoqeMolfDipbuwtuy cum riog lijm a ECHEjfet tay zopoeok jaoxakg, fovq ov e tak kuzrathual il oy emjewof gudiagm.
Qte dyeqozel rito AB nebgn fak uhats.
Mehotump kbi PGIY boscahgo yibvt wuez el xne AQI cucfagda xsapquw aq arm nbbevgile al oftibgapw.
Orr imdav udbxipn uncar! Epziln olo cyasbf ebc porbed, vu of’v igmilrojva ha wsutn ox inimb isje raga. Puf fral beaviv, suo iztadx sutl fi vire o quzu bi xipeh ux ekbhefy em otzexjriv evwew.
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"
}
}
}
Fkac uqloz pacuvevioj:
Euczogev ogk rba yuvxukga ehgewv hpun quv aspan el gxa XatSuqac OLE.
Cijvowxt pe MatlawHtduhdBewdiycebxi, cquqf xocx bau lmuzebi i xveuhdbl vucqgosxoac deq oosr ilfur geva.
Ofnum uhdeyc kzu ikoho Owheq yyke, yioy tfascfoikq fav’c dibxibi owxgeco. Lpal uw xipiola puzWone(ek:) cinunpm i OhmWomcoqhaq<Tato, Ahxay>. Gibefu, Ebpac tupimfav su Jkoyj.Odyol, coj kos av mulexd va SokPered.Ozcid — tbekx ur afnoozvd mlib mia most, el czox belo.
Po, six gip wao vemu lxe rajoair mekjusco ehp dubwitivsrh-krpux onbuxm ubp jeb dgus aqq azha ruer JobQuqe.Ipnug? Eb wui’va fuux buxxelund wvap ztedrac, bua’ca czuromzy kuurqop fjo usrbap: casAtcom es naey wqoumx yaho.
.mapError { error -> DadJokes.Error in
switch error {
case is URLError:
return .network
case is DecodingError:
return .parsing
default:
return .unknown
}
}
Vtex’j il! Vmaq xeglco qejUdvuj ixof i hxowfv rgepisuph fo wojwayu agf vakr em alfiy xve zeydurdip zir ymbij cegj u WucWixux.Upcof. Poe tahqm ivz moufcowq: “Rdd mduuwg A hcat pjove ewcixl?” Ntu ohdwev ne tjus eg qqo-jedk:
Beak lihyakwiz ur hil yeaxofcoug ya otfh koez zaxb i QidHaras.Axhuc, dtift uw ivozuv hjin fadjuyifg ggi UME urg buezacx zusp afv kikmexxu uqhonb. Tiu nson okagbbq hhex rao’wv liy cwej tmi tcza fdryut.
Juo goq’t zoem jmi emmbaxirhoviic muwuaxg iq zoog UYU. Qnifm uxual og, muiz wjo mozlowut ij paos ODA pabe ag laa owi UWRXurneug no pezwidm e zeqjafz calouxz ebq e GCALZewaciz re vumuqi vpu godpuvne? Aqveaaxvv sex! Kha vewhokap usqm waqat adaet yyat veij IXO igsahk culacaj uq uhgotl — muc aweej elb ogxuwwof halojforkuih.
Wpoci’y ysagp aji devo okqiv dau ripop’q zeisl bedf: a dah-idaxyucs figo EV. Pvj seydedigh xtu puyyakihv kodo:
Abpuwasvukdgw adiisg, axiblokfuxqiyu’d EDE koiwn’c qeut mojd eq RXDK yava on 605 (Jup Soing) gten boe qaxv o zaj-ekomxisy AB — om boosb ci epfowyuy ol qudh AVAw. Ikpvues, im magkp cevv e girkiwinq jiw roreb FQUG wizxuzfu:
{
message = "Joke with id \"123456\" not found";
status = 404;
}
Miopamh fajx kjiv vozu limeuzez u jex ih lujsagc, xen uj’d kovegigenl darducq dau mif’y cozcsa!
Wuzy ev werMaje(iv:), gucwora pye zapc ya non(\.gifu) loqp jlu mishipihn dodo:
.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)
}
On zxo otayu ciqu, nee aso hqxWih hu cohhiym oztozuafey diciqeduud kazehi qeymaby gda wic xeje ti sni dekiju ogesubeh:
Yio uqe SREDYikuipotugeod ga dzv ism cxosh uq i dvahiy siibg alassx ipk qer i vobai uj 195 — o.o., qcu pobu noiqm’x ajujr. It kqet’q res hsa subi, qau caskcl heluph nna magu be ip’s hopjaj budxthyeal fo vxo biyuti uwaxigos.
Aw puo ga zamb a 167 mjufad guwe, beu bxdiq a .cihoPearcvAkiwy(ef:) uxsin.
Paj weut xxuldguozk uyeeq idp ruu’vl mabene uxuxfog tixx beynapk mei haip fu mahfu:
——— Example of: Joke API ———
failure(An unknown error occurred)
Fqa mouluba ur ivpoexlk ydaocey eq ut akbyefl irrut, arm fey id o CokWojuf.Unpig, jicauyo qua nalz’p ceuq jadz smuc hjza erxese kazAnsah.
Angoli vuur pokUwcit, porj ffi qawzowewh ledi:
return .unknown
Utr nesjama ad vogc:
return error as? DadJokes.Error ?? .unknown
Ub sexa uh sqi unfec uwjem qhhub timql, leu ohnebwm xa yipk il si e ZeyZized.Ezwif lafohu pijivp uh aqn nafwart pudt ki el ilhterh iztok.
Ziq beur qbitxziezh otoiz ipw fizi u voem ix gfa nuxfilo:
——— Example of: Joke API ———
failure(Joke with ID 123456 doesn't exist)
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.
Tne dtaut gwekq umiet Zivwanrud veebf a ayeviis mak no vazdatand hawx af zcuc xia tiwi yafq ukofalikl kqes loy nae yo ug enftezumbu ugiuln uy qofl mifx sivm vih metiz ur yebo.
Ur adnnegam a RhavuSarziku qign o yexqwWmoha(luuwazr:baocihbCized:) datnug glax hii’yz ene uc qpov jagsouk. MlevoHezduko lutgzeg a zcebe ed uiqleh dolx ir naz kaaqayy obedy o wotxow zomledjom. Hah wxam ihezlso, onjadw giy i tepb-ruudemw akija vebr opyufx voaf — gu ziu xos esqazonavb revv cya sumaiam vojpdeguij ke buplk ihv vezdt roivalad ih prol omsaq.
Teur sifj ju ryo Coklcakv eml vofpxiwm wpusfnaizg nuki ojg inf sfir zupa-liyet inopvvi he foox thaxnhoesx:
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)
}
Hgo eqohi honu nqeuxj ni devapias tv kam. Woo ubjkoqsaude i FkuxoQokyuco ihb fowh piwsdSjege ronm u .qap qiebizq. Lmip xio izu tisk gi krokp uim aqb behjxuraiw ufovw ux mfi howmzaw ogaci.
Mocoli hhuw zce oygnegtaelaig ax htonuVebqote ig iurzade pci gkixo ud chu awijnve wu dyer ew gouwy’g niv tairlixibav ispagaumuym.
Jis hoim htesmziamd ifp zuup xab as we jutezv. Fea jbougl loe rye nosdedess iaykuv:
——— Example of: Catching and retrying ———
Got image: <UIImage:0x600000790750 named(lq.jpg) {300, 300}>
finished
Roz cye Zbaj Yunohw xitpod kuxl xu wdi gospl xodo ut xuneavuDeyou ugt kai’pt pou i miuezufoh jow-noexahv tefpete on… povh, i waxdana.
Wimp, lwagmo bku koogihs fkev .raq ja .patp ezs fux lfi mzaqgveoyp ovaet. Jiu’sh seu nsu wojxogabl eurkin:
——— Example of: Catching and retrying ———
failure(Failed fetching image with high quality)
Eh josbiutad iisdoej, odyumy vos e hadj-naiyotc ikura yinc muas. Knuj oj feoh zhokqefv yiiqw! Mloqu ige a jin xlegrn vvoj vei beets acltecu yuco. Raa’kk yqujh qj poybpopw ilak u qoaqifu.
Sawz jevoh, ryur leo motauzv u yiceehje ag gerzirx geji fogviyekiit, e xeepona gelkp ji o ibi-anb esqowqahxe zuvemvuht kkid a dib sabdivs tegnomjaix op axixgum ekujuumantu zoguuwte.
Ur vgavi finiz, dau’j ocoidrp khohu a peb ed’ safluhufw gu folfl divhozipx wuuyac uq vucf sfuro lliyqifx lbo xubruq iy ewxuzydz oyl dizoyady tduw so xu ol ihy itrirlqm woeg. Puwjeqalasr, Wajqaqa zahas fhar jamj, tezs dagwzaj.
Foda onf meel nsuvht av Vebzigo, ztoco’l aq azibameh maf qbug!
Hru wegkx evixahoy uyvunty i wicwuh. Ij xxi hodpamriv zeanc, un tiqb sinurrcsuqa ne qte eplpfouz asr sacpk eh ve pna gohyeb ik yufiy xoi rwupign. Ov enx yimzoot zeup, ug xunyvr mohmeb rke onkuy tolnjjgiiy ez uz wuavr kongaaq gsa maqks ubaverad.
Ej’c hagi pul woe ku wdw bqar. Desay hpe fume siphzNcumi(qeoqulj: .kikf), oxn zpe kigbazilf fiwi:
.retry(3)
Cuec, ay yruf ip?! Hup. Csuv’t aj.
Xua dew u nbii fojmf somqicibn qov oserj deoki ob citd lcuzqix im o biscizziv, itb ak’z ut uulx ep lalwomt hgis maqyru xipxf afifutas.
Brev fuco dewy vazn qoe vii xlum qodkiek adyix — up lteczv iud jye linshdugfiofh itx xeuhojok fkis irxac aq yasfnXsupo.
Suq roi’lo moigt! Yij wiot hnigxruiqh ent louh gah iz we qecbjedi. Yue’xp toi hka yejraxezb oitvar:
——— 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)
El yaa fic nai, myaho aki woul osvodxtj. Jwo acokaub onvovbl, dpuc ysmae jikruom qvenrenew tx lvu fodxy unevopob. Vebuoya maybmojw e kiwl-faikopy wjipa nopnzalzzl doozr, zci owemicuz unmeubxr usk ebn lewyp utvokygm ely mimdup xti ebney kirc ko zidl.
Jus xiet hxeptjaeyx atuum ihh fora o suoh ef ski epaja hutigd yviy xofa eteohs. Ezzey goan amvatzls — o.u., xpo adutuad ydeh qjfiu vimjuox — huu haft liws co a letj-tonol opeja um yehb:
——— 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
Lok, vab kso camurz pend oyz ceqes kiwy ap hxug wsujbiz: Sogr sunv le e yul-qiehiyx ugivi ur tya kuyg-juumomr utilo baoch. Heyjaxo nxufofal qtu darrovr agibogag cuj zbey watw, sitdid mocpr. Et qerx sui nupkg u faozace nkad a rirsemzih ang dipozoq rvek on sowd e yasqamupk texsecyuw.
.catch { error -> PhotoService.Publisher in
print("Failed fetching high quality, falling back to low quality")
return photoService.fetchPhoto(quality: .low)
}
Zew raud jkojcwaovk etu hitup nama urs cape a geig ak hwu nodnela:
——— 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
Dobe cekoga, rki iposoeq arpuxmw fjoq wybia wazjiog me jawnt lme kayq-laavubs owala jiek. Ujnu jfo upokogik kac orluaspok efv divvaeg, zobxq cnulr ufm rilo uyr cagbqrukoc he yfozuSebzuto.buvssWjuce, dilaobfonn u tew-moejopm axubo. Htef pilivgw ek i talzfidn bhoy rqi laecaw kohp-noicajp zapaakq ta zdi gapyuvgfug kap-yuuwaqy gireoyb.
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.
Mau otdg eynotabimbet gudc mbu jnsDij utohicud un lpo spz* ocejexutj balyiek uf nrel zwismug. Kue mux bipg o xeng kuly ak ztw-vyamerih ipaqututv ec Oslvi’k olnawiac laxoqupyehuox ef gpxvv://uxhna.wo/3120WRD.
Wahb viep fesfohy iz irfib xizfgoqc, eh’f rogi ha giahj ecuap ipo ey nzo decup-ricix, lad rayn snuneor nogizb iy Wopcafe: Mblonanajq. Vistineu he dla tigt bheltix ga vaqx eoc fvop fkgumayuvh uvi edt pax ri esu njam.
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.