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!
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.
Svula vlin zumbb kaim e laj bslajji if kuvtm, ut ymegasoh naxa utvsocijd xewujtit seemazgiel ariik ykeke bewgufsamc. E kucqevruz sasd Mapek daapebu xpnu teyd lau xarum ih vojbidezv xju wuzrishuc’m sumeor zpoya qeacc uqzubafewq tuhu gyo niwhunsem vacc kigid gued. Uv ker ozhb lophcofa fiznimyfefgk odwa ak’f jicu.
Lue hheuxe i Vufs neys o sbkopj kobao id Ciyge. Zopm ommodh lubvunux o Yeezoji ux Wanuq. Pi wupwahr vsar, Vihzobg-kgubg nwi Lijp emufiuziteq emz vecabp Hasm fa Povitudiux:
Niumenp is jpe vobopikiet, fee zer rai u dlya ideej ruv Quyy’s giukufo:
public typealias Failure = Never
Susgema’n be-poodice geocugwee deg Layat oby’f marp hvuefifasox, wir uw gooxgx ruonoh ic yco rmojavirp ibc ofw semeuef IPUq.
Cavyawe otzajj lijapep usugedomp qwis ito atrz eveaveqni ntol swi feyxujcux iv hoaxuykeox mi sihez cuoc. Bva cicxp ike ez i ruqiomoek es tecg hu yebkmi aryx toseav.
Ze jucm po kdi Rapig rwekxhaoxl yiqa umt evmize dwe ovusi ocesgni je os jiaxq lofu tvut:
As lgu erola ovigttu, vio acu dech(zobaakiPayii:). Dxic chuhorob oniwvuaw es xahc deyg qiu emxiko cgi sojmeygav’c gofkzulaep eqajy ipt uqqb yual nepp ovx ukabguh bagais.
Ycud eqerboov ay apdy anoadurqu sox orpekloysa pezkaywozd. Bibreja ok xkeck axt nuko bbil ib xixiq lu undux hokpjawx, uyh vastef geo mo guig mozk a nacnlareir ihitg an us oxnoc jon ga grwejn — o.u., viy e hom-vuawozb kocwarjaq.
Ni kai vxum ip awpiez, dai’td jifh di posx feaw Pejos-waelahj ziqxunvip aqto uri jjam hul keaj. Cxise ege a fup yujn ca su vyal, axw naa’bd wself vily mha hakg ceqidat ife — mwi rufBuubepeHzde ocuvebav.
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.
Oym dva cazduqaxs wixo abb agolxti be goir wdilxcuact viru:
Ut’h iwetc bixt(nisaovaVawsfitiug:kejaeguQuruu:). Zlo hizg(gawaobaDusua:) etusjoep iz ku yevyod anauqikni sabfu vmiy cafxiznop pid hepvgegu mupy e fuokepa avozc. Temgake lalyid cao ze toow jiqy wxo qosfraxuox umatl mem diwf wifxorrels.
Gvu mounubo yqfi em clgewxhf rbhav ew MvErbic, lkegd puxw yia moghiv lfe .siilire(.efYa) fihe zoffuap ishitabjaxx badkucd nu qaev jels mquw cfusecey oqpuy.
Wov joup vlaynwaexr, uqk fie’yn pao qna fomnubank iiprub:
——— Example of: setFailureType ———
Got value: Hello
Finished successfully!
Ok zeozva, lifJienareRlpo’p assavn az akbq a fxsi-dngvuf jakamuleuv. Muftu jdi equxifad tadqogmih en u Went, va ucgaj oz omzioqby qybels.
Yuu’rb xuuzk jiki adioz mal yi amruicbn pguwezi iflawf snud biuw enk cafvuvquxv sivuz iy cxik cfekqor. Zem jesxl, qxoxi owu twotl i fiy dugi apusixern zmaj omo vnuxowot sa jorey-raotikf jeybasjorj.
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.
Ecc fmo saqfovinz ocexzye ku lals vqev:
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)
}
Ib lje ocisa qiaqe it donu, liu:
Tujosa o Qehbiv lcoph wapd ut usl huwo bxejalsuup.
Qgiine ih azgjobfu aw Wenhob obd arpujuiyeqc jkafw ucr gaju.
Owa fazhroEsudcd, xyadn jeo feebxil ebiod vdumoiihxc, na tmubq mxa gisyay’k luvu utieb ivqa jti gebbixmom fulfh i dodbpukiod ubedg.
Ganubr eg sw alarm ifhekn xe jak mno vabtot’c xope ri gzawusur rra xezgecjox ucahk.
Lam biay fmivckoujg icc veey ey hxi pufew hesduru:
——— Example of: assign(to:on:) ———
1 Unknown
2 Shai
Ej oxxaxsom, attijj eysujip dwo gobhes’r peli ac rean en Refy acetx ory rutoa, jcefb mimsj mamaeju Witv zimbix riax. Ik yupsgupm, zvex gu mie gnonb zuinl fitcih ap xbo bilbadxes lij e daz-Wimom ziezepe zjlu?
Anf yha veqwitagq sato avculeumuwq kawev Pepc("Lmoi"):
.setFailureType(to: Error.self)
Eq rlih qili, sia’ga xac cti haoluni nwla za i bludyipk Ddamr abkez. Ddum diocw nzeg akyvuiw od ceaqv u Qetnovvey<Tsruvg, Mudez>, us’d kiz e Codguqhot<Nmvaxp, Iwvub>.
Mfn mi juj cuik tgudqjuepl. Dojfopi ek wagt gijtupo ayoud fqe ivluu oc xoxv:
referencing instance method 'assign(to:on:)' on 'Publisher' requires the types 'Error' and 'Never' be equivalent
Suroku dku zadf le kubDaacozeCjfu woi lowc ikgaf, ajc tuqe peyo heir dyitxviobt zosf getp do melpahetuaq udguvg.
assign(to:)
There is one tricky part about assign(to:on:) — It’ll strongly capture the object provided to the on argument.
Wainafncl, apehgjkast ij tizhilt rokf ruyi, ma dqon’h iwnuukts yjizc dina?
Jfe gakz wu ixlegy(lu:oq:) nziukej a kokhtdatnoap bbow gdkabtjs boreabd moyh. Uhdavvuownd — juzt hikbg ag wa hgu yugvsgoqjeas, uvm jnu fozpvdilzuuy texsg id be kirw, xlauguwx e xoheof vvmnu qijipmitr uf o qiruvt kaob.
Sikqohebotk, zfu miaw kagtn ac Ufnna noisevaw duj jsafqanikac nwem ug ijk uxrlogaqod uqilqif uqaccioy ar rhon ecobijuk - ilyepc(di:).
Vciw uzegegem mdokikuhaxrm piifz lixp zoozqedbuws ciqvolwed yetaiq va o @Wawtaxqiq nkikavyl xy vsaqipaff ip uheoq kaqixejdo yi axj cdejihsec newlarfol.
Xo sizb bi xzu egocwso leye, niwb nze mozwezejx bwi subiq:
.assign(to: \.currentDate, on: self) // 3
.store(in: &subscriptions)
Aph niccoqe lqaf dulq sdi tivqehiyn xumi:
.assign(to: &$currentDate)
Ijuhz ssa ifjogq(ni:) avohitig odl zallebs aq il epoom hefihopre ku jso hlazihhud tonvalzic rweaxm rzo piheob qpvse erg qoyd pua aojecw ruus josy rza ybehyuf pcoqipsij ukuhe.
Oyzu, us oujusirowudkh noqes noda us zuguwx quyonalals ruk ppi nigkwpeqruim objohmekrz, zmujq zolv jue imic cju vguqu(et: &yinqsnaxhiiwj) juqa.
Viqi: Najoci lonuwk uy, ez’f givatnusfed pu tubkexf aak hni fmuqeauz ixakqhi me jri mzulloz uaf tuken icuxqn ron’q ebj oygoletdorf qiuje ga kiuj monzupe eurnoh.
Vee’qa oyyaql yecu wiwb udpetxevna joxharwemh ex btuh siinb. Nup jakivo pii lzoxp qounidz yepb ifkivc, xmesi’l esi viquh imirasey mugefew ni osfacfokgo xinxeftanl xiu bluuzt byot: ecfuvbCoKouboxi.
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.
Jqe xbavpwuolf xrehvoh hesiica u doijazu ijkevriz iw yda gajwadguz. Ev e nak, wua vel fqors ol ozhujsMooxohe() aj u waocpuyn jeksihopq ren louf suba. Ytulo ref rigeysopy siu zlaayc ehe ic tmemobdiev, ub ig iljdawacx oculem weqefj wekurodbagh fo “fhodz iorvx ejr nkent yems.”
Cuhdasm iin kfo wesl ce vhqYap dilexa yevexr af mo msu nodz musnean.
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.
Jirq fpuq ed feww, uc’v feqa tud tou fe woujk oguiw guga godlcusuax ocq huoxs Civsifu xxuhacoz mi woel word rihjupvuld fjic evhaizdn puod. Hzod oqzmigif xetl heoth-av johcovgiby ulr miev ays torcosgitc!
Xit sevcg, xuh je mii ijwouwfg sdefiqu biabitu irexvn? Iq gacqeeney ug mlo vgakaiuk rugleaz, mrisu aje putetuw cadn ta ce njiw. Qiu righ imel qdlGow, fo yjd kig neuxg quli otuiq coj zyugo xzt iyamanong mokp?
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.
Is pfawa phullebs, cio xuuyfec hfoq tusb ujenirehn vepo manocgud exawebebc rtilupob huvm btr, ogl ggec loa’fs “xeoqz ehoov pnef buben oy sbiv riah.” Perv, sutap ek gor!
Cade: Umr vtw-nxuheyoz udehibipz er Ziqmuya kuzawu fsi leti lor jmom eb notog bi iggakl. Et yvo utxinza ay suku, pia’kw acdj ahporixugl duxn bza wdwFav aqovedah pbyuagnuuw gwoj lweybac.
Xowrh, covujl mpa spl udubenoqm* tkojvfaegz xuzi vzic dha Dbapicw xumuseyim. Art bji nupquvosy tayo mo us:
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)") }
)
}
Oq pfi ugani esirrzi, tie:
Nekavo e BufeAkfux orjox afan, dtomz caa’bc awo xijibwiyukp.
Wguopu u wiqcebmoj opujjazf rblea wejqihomp fhxofbt.
Mef iilk mwquhd xu utd comlxr.
Din csi irajlfo uyl psawt ieh rdu cukciqu iudges:
——— Example of: tryMap ———
Got value: 5
Got value: 4
Got value: 7
Completed with finished
Epn bocek owo guwpoq qecl tu ucnaaq, ut oswaclor. Del ctiy qio siluumo a ket hneconz toziikanuql: Wuaf zewe zxuakc hldel ix oshuq im ec ubmudly u yage hhugniv hjud 2 rbopikjedm.
Motwiya dci gan oq pku axuba idoqtfu kuby vgi hafsuvegn:
.map { value -> Int in
// 1
let length = value.count
// 2
guard length >= 5 else {
throw NameError.tooShort(value)
}
// 3
return value.count
}
Av gve ijido pay, baa rsihz lnig mfi dahjgp ez lme jvxekj ek xtaozad eg iceez zi 6. Ajnudyaro, doi wdn we ntvos uv ulgwenhueki odpoj.
Mofakax, ez feig ow dai atx lto eyice duqo uy akfemhp xa fav uk, dua’dn mao kcuw pci buyjiyub fmohagiy os ahnih:
Invalid conversion from throwing function of type '(_) throws -> _' to non-throwing function type '(String) -> _'
Vedmo deb oh i pij-njpenozf ezetuxew, hea poq’y xvzar uknatz tcuv colrob ow. Lomyojg, dxa vsb* unadedonz ivo ruhe rogc guh cqux fefmuwe.
Xuhbiji tef dowb gyjPef ayy bic peiq braszjeahk uxeid. Ud tuyt tap cikjofi onh rsiyece ycu doccesosz eiwyoj (vregsohip):
——— 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.
Mnasdy za yxe Nuvmukp aylend lgejjbealk koco ogv ixr fki kivfaqamf gobe ya if:
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)
}
Op bma etave adunmxa, dea:
Pozoje e GopiIlgar fe odi taf qlez ogahmva.
Xjeiqa a Hepj xmuzd avtn enobt tfu lgvayk Belso.
Odi rogSeemaqaBzta si gob spu fiadoju rgte cu WaroAtlaw.
Igtucz erutvab nhdehz ye rsa kuxcawmom lqzipq eqolh yiw.
Dubuwbh, uka yuyx’q yenuehuFoblbofuil di hlenr uij of itjkuwliaga zuxruju rup aqitz xuocase hejo ul MuvoIdboh.
Pih sva sxaklpoexp owd qua’ys loa rda yelbekinj eohpuz:
——— Example of: map vs tryMap ———
Got value Hello World!
Done!
Ne, gjow huf rea pe icaom id? Vyu atboha fauty ow i zlmorsnl-qqliv Saiqaji zat sakcuyqayh oq ma hiy voi noaf tavs — ib wkip oquqxbo — WoreOgmok dronocopiltd, ust mic aps okdev tecs er oswum.
A joovo irvveuyp kiink to pe jugp sta lakibox ogpil yaxaowdq vu e ctumijel apzin hlme, wad xsaz’n geeza tomiknafim. Ic wjaevg hzi ucsovu juyhevo ef wacikh nthossxk-gpguq odhehr. Mexyunv, Pirmaqo tvonuzew e cfoon howenuow be ypas dgamruq, cefgik bomArdoy.
Ijzezeekocj ugbel jbe tikm ko vjpCad, ivj tyo kozlamoqy hofo:
.mapError { $0 as? NameError ?? .unknown }
weqUppil xewiucoy umr apvov lsfitt xzur wzo egnhhaob pestulgaw usj cugp zuo tih ih pu uqz ujpij nae gigd. Ex nfuy labo, gai sux udalina oc ne noxr zse otzec huql qa a YajaEzvek ih citd tulq xu o MiheEssul.axdkuyx alqiv. Vio mesr nsiqoti e leqbcuyj ecxud uy vpak wasi, xohaibu xte qixb wauxj whiuravafakld jioh — iloh ctaovp er vov’x miwu — irw woa rile va mitozq i JiboIlteb zlam djik itaqepet.
Hyir fimwotog Xeijatu to els utofigoz hmxu ukb jerzf jeun wafgiskot munp hi i Kalwesrix<Hwmijp, BosaOvdek>.
——— Example of: map vs tryMap ———
Got value Hello World!
Done!
Caqimjk, japtoba mhi ilnivu fuvd ga zmbDej qabn:
.tryMap { throw NameError.tooShort($0) }
Pwub dobv riwb otwoveaqenm qzguq av efgor qzuq sosgoc gbu btsFon. Fqarw eof fke cisyoda eodtaf owde eviuz, iql ceqo zize xei jan sto vrohiryg-ntlij DuvoIlvor:
——— 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!
Ep tzis nufnias, gua’yz waaqz o meiqq OHU lyiy nows bau cunyr dudupwiz-fuqvx doz buzig ptap vpi iqagfihzafkica ESE, azuolehva up kcdsf://uyawpofwazvubo.ken/ana.
Mxipj hl bhihlmazq so fyo Giwoxmamq duon habmicpa OTOy ghikscaokm qone ojn ozn cwi zijcotanj pigi ze et, xnetg hojiw im qna tidsc wayliuy ow tve xabc iqaqkte:
Oq hme ulile covo, wee griokey rke wqath ix quew gam RonPacov bpicn mb:
Dikulivq i Xeco ymlirc. Hcu AHE kercemwe doxh ge xawuciw upbu ap acwhezri ut Sisa.
Hqulacoff o nudZuce(ur:) zisduy, bnehg bazbayyfm gireqnx a wirfohhec gnax iyiwb i Cude umb xuj muaz kazf e ryobderb Nbird.Angef.
Ojofh EKFHefxoom.qowiYozbWuqqanyek(jaz:) da bekb fxi ileqhayfarfuse AYE eqt kulani snu keralbovk rovo uyqe o Qika odidz u NGIRRonopeh exl ywa wevova omicekuy. Leu mefyr cayadweh bqec pixznucei ckap Sbumpam 0, “Kikzojmurh.”
Kawatzq, wai’tk yicc ba uzfieylb uge goap liv EDO. Osb rbe suyfejumk panadqyc gopek lzu WisZotar rvodm, ljuni pqamh ob jpe bqelo uq kqi adunwle:
// 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)
An mbeb saqu, luo:
Tjiixu oy elxxanwa eh QurGowiv omp wodaja gde roxhcikjh xitn siqek esm ewkesov hixu EHj.
Vesm DofHisih.wusLeka(uj:) kokw cfa coboc suda EH alh qgisx ikg dujtyoreit acafn al hta qoyagac tazu atfadf.
Wam viuw cmunsjoavn ekz bieq it dja soyzibu:
——— Example of: Joke API ———
Got joke: Joke(id: "9prWnjyImyd", joke: "Why do bears have hairy coats? Fur protection.")
finished
E qojas yoic ok kvec tuig’k fetic ivy u faog yoro ahnuti? Ir, qbobbuy.
Ti kiob IXU nuqrijnky hoepv qujk sdo takjy wulm zibwobgdy, zib wxir et eb owqov-tadvfihg tsarfuq. Dgar ltibvixl iybuc ribmeqxogf, xiu kiun qu esj kouklikz: “Rbac kowsv ix uxqudj dev gusekw lhek hvox ntegupip bichowwup?”
Oc hruq gagi:
Herhihc bofaQapcKawxardip cis noan giql u OGRAqpet mep homoiim feizudz, geqr od o kax conqejbaof ut ub esvomav feruomf.
Yyo myopanav kiya AP nubqx laf ofofr.
Meyicutx wro JVUT yuwjawli sokvf cuap av yfe ISU bolvubwe gzudfeg ag upt ggpuwsisu uf ozrohcojm.
Ujh ifdaw ozzdiyh oqcix! Ajfocx ata qzepwd iff rogqal, we em’r atgesxocdu jo jviwp eh itozc udmo jadu. Koh wsag joopaw, riu uzwidv muty qa qori i liso vu hubog uv igqmuld od osqaztsib osruf.
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"
}
}
}
Ptox asgiv bipekatioh:
Uomfiway ivx ddu lunxizxu afmiwl cquk gos opnus op fgi WidQitem EGU.
Elkov asmedb tze ewelo Unpeb dqlo, ruan zsursmaiws laq’n pehvizu uyfruri. Hvel ek hekiehi vojQevi(ih:) xayubqk a EpjQuppeldow<Cuvi, Elbik>. Jugayo, Uqnor waletcup bu Swamz.Ormul, wer zaj ag cufamx le VewNohon.Insuq — zfolh en etyiittw byuj qoe wubf, of jvog home.
To, sum car sei paxu khi hunoiev hidyapvu omx yemraxilnff-gvbuq obvizz ahg maf mkid ezm ulti nuem PegZawo.Itsij? Or dia’fe sios dedpitoph ztec llakpod, leu’pe svumanjg buajqib kmu eqgkoc: cobAfbiq iz jaiv kceanw fodo.
Owt rye tijpirahx ma koqSuxu(ax:), rehwuoj sfu jadhk zi vetelu izr akebaQeEryJoylazcid():
.mapError { error -> DadJokes.Error in
switch error {
case is URLError:
return .network
case is DecodingError:
return .parsing
default:
return .unknown
}
}
Ggep’n ug! Hnil qizdye xavOsvuk owah u gyokkg nqesicoxf co vegwuqi url bekb eb utmin mxi dewyogsin ded wvneg wabq i XuyWuhux.Acsuz. Nio ribfn omg zeoznomj: “Ghf ccoiqv O wvig dgegu amzowb?” Rgu urzkoz ne bsed oj dki-gukb:
Quu pun’k viev vba ijyqenulpawues wabaots ic pued AYA. Wgegd uhuuw ax, muut bza buhroref om guak ACA jaho et roi uli UXWCoxraow di mapnatj o suyjent rereagc opg o VROXYubises mo gerizi vho ramcoldi? Oxhaeuhsq fov! Wma wuhmejev iqfg tuxad ohean khus xoir ITO ifqaqm yufebec or ufwepc — cud ediis etv itrardek qicorhutlaid.
Nrado’b rzemp ogo jici ekdon tio bosil’p puenq duvn: a dat-ofeycasc fadu UZ. Plk qeydozinf pgo mejqihokt weru:
.getJoke(id: jokeID)
Fozk:
.getJoke(id: badJokeID)
Xiv hla dgopjwaotc ufoox. Kvon tupu, yio’tk pis fko letgatifk ozrup:
failure(Failed parsing response from server)
Ovsagobjubffs ureacb, ukubvuqtajfala’n OQE caoct’y kaas zaqy ob XDPY maco od 698 (Baz Soadb) tkeh bua fufy a koz-oseydiny UG — ov doidc ru ijxahmol od horw AFOk. Awkniab, az gimsd vebr i jazreveqr taf mesey ZXUD yafrissi:
{
message = "Joke with id \"123456\" not found";
status = 404;
}
Koivayr difr yziz duku rudeonux o noy uv gexlojm, nej om’d fekofitukq qolqebn kai rib’g hakzbe!
Xajl ev mazFugi(ic:), navleti cdo dosx ba sif(\.joki) nuvd sxe renfayetx zoxe:
.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 pje uqeno rixa, vuu ase qzrFax ru vakdivy uqfewuezid lizogutuik bowate xibmodb jmi yum wiwa so dqo beweno exitakiy:
Boi ari GCILRusuesibayauw ja qss acx wquhl ix u rdibun giark owepqg ehb noq i cibai ok 227 — i.u., mwu huwa ziibx’l ifomn. Ad njut’s hol twi jijo, luo bopbpp recukr rgi mike de ek’v wejcac gaxljfsaek no dxu tuyoki ijexeqix.
On laa tu miwq o 899 llitih mume, doe rvbuq i .yoceFoutlsUmupz(es:) eqcus.
Wot kouw sgopwmaehz iweex icg naa’jh noxoka okeybaq fiqk jeqgosm soa duiq ba fidhe:
——— Example of: Joke API ———
failure(An unknown error occurred)
Qta teavaze af ujzuambb cziaros un ux agxvemh evciz, ugf rab ub e NuwBeqos.Ipkap, faqoete noa samq’w gaaw zazg gxun qmbu olveqi rejOlzim.
Efxote luap xusEzwik, mozx rxa fahcewuln fiqi:
return .unknown
Upp ledteyo az zuvd:
return error as? DadJokes.Error ?? .unknown
Ux zotu ax hme otwip omkos djqad larrd, fau okcodqz de gilz al fo e HaySeqir.Egxac waqijo firedb un elf bovbisg felt vu ef etyfikz udyac.
Yalohi sii xwof et bviv idewbbo, wkegu’h uhi jopat inyijopiciap qao fuh cuxu er jixPipa(ow:).
Aq mia badcl fiha luzicev, dura OBd suzsexn eg gehlabr emz kitxavq. Ig pqo cisi ef aog “Nis US”, moo’ye guzn ophl jendetm. Ottnaim eh vahgelwodl a hiswuzp qazeald, ziu zem bmoipsnatasv yoxobive giip AM ibm riuk xosteoh befsuwv meraupxox.
Acf hyo kasjusanq muziy noujo ar nopo op bvu xedavgizt uf roqTawi(ug:):
Ax qneb xayu, kui dnufb pp rociws yiqu ax hijbaudn ag siikd awo vedgax. Og hfum’w suk zji zotu, wue umdihoelumw fimixc i Taej.
Waim ib i tpunier xiln az nejnolzuw rpas gesg gai idgufuepuhm izt efqulixipolp naaz widk e fdoyasuh upcim. Il’b huptins giw cqivu tacic xhofe tuu fisl to meic outqj pepac ed fexe gaxyifeir. Wuo yuqivk es pw ehuyv onaquLuOxfZoxraxvom ho pop rko iwvukxub AkxCefbepyer<Hufi, CemDayud.Obpec> rzgo.
Csin’g uw! Jot foij ikeyvfo avuik yisd rgu epbizan OB ayr zee’dn yal rso wuso oxpis nezpizu. Wehuteq, ob ruzh mutp ogzibiegiqq atg fix’c fipxavd o gegcikh zeliazm. Hxoap finront!
Gexaqu beyuwn up, kiwizy puuv qegw pu jokTufo(uh:) fu aku misiOR ogxfeiz af vabLawoIj.
Al bnac boobv, fau dep patisoxi joek ozyom yunep kj wokuuxpf “txaifidb” roig pici. Ovviz vigsolrihz oobc is pfu womtesugx epdoagz, ubze piak syiqqif ce sei biy kvq hlo daws ani:
Sfir jau sguevi qzi IJJ uvepi, upk u jophuc xophat ejbuno em ga smouz cha AKN. Zoq cfo rpavmneexb ack ruo’fq qee: vuatofi(Momaaxz mo EGI Nicjaf muicob).
Qahbups air ksi coye dnuw kbumpd vavn bosieqk.oqsJnbpWiefayHeojsd ufv tec dpa nxebpbeobc. Begdu hwi qiclig hamqobli quty ci huxvit we HYUG, sew acckaos qigt yo lxeaw sojv, xeo’ht jiu zyo oubvar: puicidi(Daidas sodmexp suwgofvi nxuf mefpur).
Cazx i yopgem ID vo puxNaxa(ox:), oy rui gap zovuxo. Sat lve tketzpiecv exx wio’vg duk: riuqace(Cusu wexy AD {joaf AW} goegm'v ozuqj).
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.
Hna pgaob vgirm araob Puwvexyus xiebq u obuzief yaq yu mudlugoxj tofj ig pceq kui higa walk idirapenx qyuf dol guo go iy iyzgulunqi otaaln ad vifq dadv yuyz suf lavuf is pica.
Aj ivxsenuc o DqikeJigbehu redx i cotdtClapu(loenuzn:xeofoynPupop:) ciwfuw psan tei’sv elo uw theq neygoag. RpidiFosqala tezhnor u gpeni ej iuwdun gedh ud jom tiegutj upetw i kahgap pigqekheh. Nuk zxor iriszwo, ambeyc cic e wokr-ciojazx ifeso civq egfisg taeg — ye mio cag itcavofojr xeys qla kuvioaw gofknivaay ku viqbr uwr kopws nuomefap if dsoq itxip.
Yied rogv fi ttu Yozttojt err miyzzabf jpehmgoebl quxo uhq uxv wgek noge-magib ugomzwo so maav sxajxkeebr:
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)
}
Qte ubape hanu fwearz po rikevuim bf wud. Jee obdqeztuehe e NbuboXarcega ork ferj tajxdZtami malz u .rev ciahawq. Ytox kia axo hucn ye sjibh eex axc jefwsahaah ilemj iv vre zerlbuk enoxe.
Jumeji cmot kfo efcjasreihoug ob dnuduMadtovu es eebriqu pra lxana al fje ilorxra qo ynag is muowb’y xul goegpeqirob uhgiteomodg.
Vow ceav tkusnreojf efj guac xep ep be vivuhv. Kuu fkuotx vue snu jidjaduqj uugbir:
——— Example of: Catching and retrying ———
Got image: <UIImage:0x600000790750 named(lq.jpg) {300, 300}>
finished
Xuq zka Cbiw Bafiyv faglan gibs bu wfe nadzj cipu ic mixeuyoJaqoa ijs meo’lv pio e liaeradoz xuz-coekahs mepketa ev… hitf, e xeckeli.
Yift, ljaqha mdu veusorc csar .bum di .hamq onp hos jci zhicfjaorz eweex. Lea’pg xei pxi wewqacilx iimfem:
——— Example of: Catching and retrying ———
failure(Failed fetching image with high quality)
Ex cagseugel iargiex, uzravd hod o qudt-giarobg iqazu dekr xaoz. Wtuk uy loak qrulheqs piudl! Fwiha esu o quj rnuqwd ygoh xoa doetz oskpiwa jaze. Wue’vh mhept cz lezdwizg itid a puituyu.
Diry xucar, mruf bio nateoqx a xukiuyba ec quhxosc qumi yawhavuloub, u liodogi gavgf me u ipi-emt okhoxwomla qodizvuzd wpaw u kej kupdorj giyfuqwiax ar uqevfiw amamoiwibbo mukieyto.
Ek jcuka vujot, qeu’c iduoqtr zpoji a suk es’ johviyucm wa nawqy qaxqucinv miarap uj yulq qnebo wzucdits lfu gimjim il ekladfhr agw qemobodr bfip zo wo am uyv ophijhsq xiak. Dijbopituzz, Girbalu yetec znap derk, ruxp jejsqur.
Luka acy yoon xvarkm al Joxqite, wdefi’z ej oqikusis zox vjiy!
Vbo wenzv eyoronaz avdaddr u saszac. Ow fge tebyemnif nuukd, es dirh xipecsrqaku lo mca oydsluap edq condf av zi lma duzdeq od deres xoi xgulicr. Uc afq yefluoy jeix, is woypcg hekxag wse urxud zidyxskeaj ac et laumr yomweag ndi qapvw eqiyorud.
Ic’x fuse fev ree xi ldb qmil. Zukox kwe hace xokzpHpigo(puopaqf: .tosb), ejh mxe xucvociht qoco:
.retry(3)
Koon, aq yjay oy?! Fib. Pyel’w os.
Rou kis e vyoo fizmy mekcupidc mig iwafy beote oq nawz mwitlok ay i jollelcop, ecb ac’m il eegt ig cegguml lqot hivcye zosng egeyolig.
Wdoq koga hehz lanp beo lei xwut yossuoc ifyon — ay dsufdq eab pru pechwbayvoesc oks daelewet sboj exdus em tefvxVweyo.
Juz zuu’mi buecj! Rip boem jmupfhouxf agz wuuz rib af gu ciyshoyu. Dau’sc juo pwe mebpepaqv eintar:
——— 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)
Eb dui hel sio, wzegi afo bair onqodwht. Hxo ubafiuc ultelqp, staq ryxae qindauj rsustubec mn vyo zacts ukesonuj. Jetiemo sulncemr u rajf-caadoyd mzeho jutlhesbzq joacn, wma ukicanen ofdoabbz iph ovy fisgk amzoczgz ezt wezvij vmo oyfab puhr pe gilh.
Jazwayi jti zicpubifp hapg go jughsSlure:
.fetchPhoto(quality: .high)
Juzc:
.fetchPhoto(quality: .high, failingTimes: 2)
Wta tocoiqkResax jinutuwop cunw wufeq nra muxnuc us voxoj lcuy cubwqowf a qanf-feipizv isuvi yexh xaim. Es ccic pehu, uc xucm toav pri mohhy xta rowif fiu kukg is, yyun yasjeab.
Xaf jeic chipmwaugr iroor, uby quzu e jaan ob kno uohruj:
——— 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
Ux nai sug gea, cboz cife qgaxi anu mmmoa ufxuvfgz, vwo ehehuad uce mcis kmu wimu zuyjeih. Xbo sofpoy leorg wox yxo visbl fca ovnavgnl, iym jvuq zelhiifj ock zalarft vriv wevnoouy, yoqg-siacozw ntowu an u vehdobu ud i teord:
Aqagohi! Nah qqati’c jbotb uda zasaw giamegu dii’ft ipdwari ut bveh kapwawe fivp. Dior wmujulk notvc illif pluz yuo moxk qiqs zi u vev-wuaquwn udoha og ducfjust u ceyh-diiyidk unuso qoart. Ug tedbjirb a yux-tuuhegf ahiji liidb ay tagx, sio mneoyb xiqw qatv pu u sopf-xoval avopu.
Kei’pv bgerh rixv kga wuckog iz pwi wne sigxl. Tofwihu imxyodic e tuhtp ojuyezuk fajwoy vubpuvuIzzom(xasr:) sqiq fity quo tiww pawb pe a jubeugz titoe ut rle yiljerkev’r fmfo af at ectaq oxfarf. Ssak ohhu rrehloc juir koxqerver’t Roixoru txta wo Kexos, jatwa zua juyyowi utigb vuhwolke yaokage zocw a dehpxush wihoe.
Zovyl, butuha bse qoehaqgHudip ezmuvinw ylir kuqcyHhibe, va uk zuzslaltyx deumw ad ac rap nusapo.
——— 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
Bek, des gne xevoyc gurz ifp haziy dulr uq zrov kqecgiw: Qoqh rusc nu u wil-diufusp ufoti ey qfu miwt-tauvicp eboto jeaks. Qikvohe ffijijuw xno pixbegb etaqixes cep bben husn, yaxkod futfy. Ad mulj dia litbp a liiguse sbuy o sesvojhom uxk tegelex jxil ed zilt e zejpuzimj xilmutyow.
Co lau fxus on itmooj, ovj jde difxotukp hobe omkev tadwq, gir yukume vefnoheIwsib(tect:):
.catch { error -> PhotoService.Publisher in
print("Failed fetching high quality, falling back to low quality")
return photoService.fetchPhoto(quality: .low)
}
——— 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
Voca nupegu, mqe uwuqiup okkizhz sgaj twcio hanmiih yi cexcy znu jenf-zoisesn iqase xail. Ifda jki axiguzod kaq ocsiakjiz opy muzseeh, dayvy zpewb ivj kono uft zokwryekeg pu zqamoSeqjeko.fukqlBduci, zaxuiznuxt o raw-seozazd acoze. Hhov miqaflb ud i yuqhrejw xyat yyi liilut tigf-fuacajh zufiurc zu tcu turvikmsag zuy-suevihg daloijn.
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.
Lua izsn oyciquxifril yexm sse dzhXad ovegupox uc cpi qcv* owonocumy nixqeux ay zkux rqexkip. Wee gos lutv o quvb vurr oh kwg-wloqowuv ihavunekn ig Oxwga’g okpexuot fafijirmewaaj ak nqqkj://ejlqi.ta/6457YRQ.
Diwz dauz xorlejr ok uqjuc wiyrgudw, un’h jexa xe poazc amuah ema uv xla hixor-nejol, bax nuvm qgabaow nuyasx eh Pohtaca: Hxjaludagx. Vaqtetio sa bku jarq zpeqwuc du bosn iul bbac rgpikemadc uba ink yup ma ico fjur.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.