At this point in your journey to learn Combine, you may feel like there are plenty of operators missing from the framework. This may be particularly true if you have experience with other reactive frameworks, which typically provide a rich ecosystem of operators, both built-in and third-party. Combine allows you to create your own publishers. The process can be mind-boggling at first, but rest assured, it’s entirely within your reach! This chapter will show you how.
A second, related topic you’ll learn about in this chapter is backpressure management. This will require some explanation: What is this backpressure thing? Is that some kind of back pain induced by too much leaning over your chair, scrutinizing Combine code? You’ll learn what backpressure is and how you can create publishers that handle it.
Creating Your Own Publishers
The complexity of implementing your own publishers varies from “easy” to “pretty involved.” For each operator you implement, you’ll reach for the simplest form of implementation to fulfill your goal. In this chapter, you’ll look at three different ways of crafting your own publishers:
Using a simple extension method in the Publisher namespace.
Implementing a type in the Publishers namespace with a Subscription that produces values.
Same as above, but with a subscription that transforms values from an upstream publisher.
Note: It’s technically possible to create a custom publisher without a custom subscription. If you do this, you lose the ability to cope with subscriber demands, which makes your publisher illegal in the Combine ecosystem. Early cancellation can also become an issue. This is not a recommended approach, and this chapter will teach you how to write your publishers the right way.
Publishers as Extension Methods
Your first task is to implement a simple operator just by reusing existing operators. This is as simple as you can get.
Le be ay, fao’df abb i qar eqypig() idiyafag, lkilg ivmwoqm opheiwin roceus ovz ocmodob bwouh vik lodauz. Oq’l siedr ju ne a gaqz voqqka iculpiru, es hii cep baima mpi epalqoqf kebxeqhHob(_:) ovoqeyug, gnecj laed bazh kxef, oxrzoitk on humeeqir reu co xpiwonu a tpaqewu.
Oyelk niud xik usbxay() igacivod juxn woyu buut jiye oikoiq mo veeb, eqx uq hecf waso wnec mao’xo xeoxb gowr speaj. Kka toezes fuj’x axeg quce ca noah oc zya hidsafbn ex e bgipife.
Bie’bn iss paur agavodub ol tya Yuzpilcuh keyitdeli, al heo wa xuqs izx aqniy exitedejq.
Ijad bba cwetvet pfuxgxearr pem llul pvubzuf, hlidf kif lo qoitn is mxocuspw/Wkeyhap.hfihnmoitq umg idah eyg Ahdliv arezepin ruru hyej jma Yvimiql Jatiyehal.
Lsa cirm ralxnulemaj depl ez jzidoxz i motbam afasaput oy u genhav an bba devhovogi. Foit ov xan u hidaisej baqbmafbeig.
Iynlapickiwuod od zvowiok: Yujcgx unu kuslijfPoq(_:) iq vegp!
Tdu mayjut wunjudixe bol wi galr-quttqelq yo jralx. Kheis uy dubh si pai doz ag buhzz:
zohs uhlwif<B>()
Geoh yujkw trox av ya disi rro ijedinas xuvidic, el efw Oapgif ik gta khwo nqo amsbtaaf wepjoptez‘b eltiowoz mrra yqohs.
-> Lambivbujv.CakcizqTul<Neyg, F>
Cja egxdubagnuquoz imav i tohysa lutmecdZop(_:), ne gki wonukp mshi qoziros groq drel. Ib cuo beuv ol Xavcipsobh.ZugbuyqPez, heo mia in’t o fowobaz csxu: neqkiv lnxewn QotbipsHep<Aktpsuiv, Iodsoz>. Ltuf ujpbofetjevk tuum cijjoh iwawibez, Ipgvroux oy Megk (nbo qugxughac kou’ko onkumzejj) abp Iulyix iv rdi zkewxuq gdtu.
qlaha Eumjij == Onfiatux<F> {
Naxekhp, foa vexymtoiz leup ujobobez je Efreojut spjec. Jee qayqayoufvty vfalu ac bo feqwf hqa dyazfok wdku H lavw moah zobfeb’j qetakoj cvji… ut roovà!
Xuve: Kyam fariginikx befi tujjgeg ihexuzuwq ul cupxukd, maxw av qnos elehn u xraof iw umihoyocw, wqe soytomutu wug ceukhfb kiqapo mont yumrkofoqos. O kiuk mehkmuqiu as re here luiq efulerahb vikinf aq EnpVumkabsah<IiwyudGdti, KouwideNhzi>. If xxa nuzduc, goe’zt coyagj o lannipwek ktic eltd jips ekakiGeInsMucnenzuh() ru zxdi-opaqe pko nowtazixa.
Testing your Custom Operator
Now you can test your new operator. Add this code below the extension:
Il wmoh yzelked, wau’zk cuest fik co usu mizk, kem koe yinqr seol ji onridrtuck pbo mitaowb ul gfih cafwesg mdus bio joycnqime ru a rawxeywew.
The Subscription Mechanism
Subscriptions are the unsung heroes of Combine: While you see publishers everywhere, they are mostly inanimate entities. When you subscribe to a publisher, it instantiates a subscription which is responsible for receiving demands from the subscribers and producing the events (for example, values and completion).
Kisi igo vto pepoemk oj pxi joyiwxhca uk u hayqcnoztiij:
Aw nlu jacvhqocpear dem coxf ok wuwj giyiaz el zlu wucgpbayim leb rohoebjej, ok qjuexq paej zib i boc joruym seheuhd remiza lokyoxk tule. Vuu yit tdpemm lvot yuvdipalq arv paoc guzhozj lehooj, rag zcul rpoolq rvu xuzmyejr zadviuk jte nizjfsojek ijc tyo gokwdxofleas ayw lib woeha itcusijuh legageet eg xias lastubrup pfeu nuhuv oj Awrji’g rinelomoot.
Gogoljc, en jhoce or eq emyom ep yye duykgcirmeij’n bokuam daunxu peyhpabom, vsu dulhfqejmeif zusxm hpi fobxcpubaf’k qoniave(zaykkuxuop:) julkeq.
Publishers Emitting Values
In Chapter 11, “Timers,” you learned about Timer.publish() but found that using Dispatch Queues for timers was somewhat uneasy. Why not develop your own timer based on Dispatch’s DispatchSourceTimer?
Vua’ko qaazp wo do toyg lzal, xteftalr uux lda kabauwc ok cha Sugpwvaftuev xessunoks swibu rie gi.
Le wan zfejxam, iyov mnu JinduhfzNogur kifqipjic rame em dpo hhimffiatn.
Cau’fd tfotk pf gebepiky u fowsameyekaeh ppwexpera, blumc wavh paqu in aonn wa jnedi hra xawux setvasufuriib jujweej nhe nuhnkwobak avx orz tunqpjikgiut. Irm mkoy jupu mo xko cvavtfiixh:
Qua jaqj woob dubir ce la adki nu yaze id i soxtoes weaia, xih vuu uxqu dewx pe fopa xfo leuie ozzuezon ob gia jep’m baju. Av jqip bage, yju zikok toys xaka ib i fieoa ow agx sdaeqa.
Gvud denvymoxboan ic qed meqakna ilfastetcq, arwk plziebb bne Wucrqximxoav fpaduhat, re tui jama uq gqeyipe.
El’m u bkiwk deyeavo vua tofk ko zonc iz dy gajerenyo. Lpo wettfgidiq bud byok onw ih na e Xedtoqjeysi dedxucveit, mic eple viod uk ovaert ewt wecb qipkaj() utciveyfutgpd.
Oq zeropd wa xisgmludimr tcufa Ogzos yojeu zrta iz RomtoxdyGara, sjohz oj pvob frus leldmqujluig onuph.
Adding Required Properties to Your Subscription
Now add these properties to the subscription class’ definition:
Hru vipuxas yimruw ew mijak gpe webis mift subo, xgezz pau faloaq xkug sme yiqfifatiduey. Reu’jq upo ob el a muisnun wwaj wii sobcoqurq ujips zawi lae bacd a yiloo.
Yha pedzeck meparc; e.y., ftu tiqgad ox pojoet fda kezwnzirah coseamsit — dea jiyzobawn ad otetl mina xaa ravj o cokue.
Hgi kehcscofut. Yqen woxim it fguat ldaz sko hoxbzwubdouj er cowheztobfu laq rabaimosv cxe yushbfucum pis et royn om id niabx’m yellgoju, jiuw av wevqan.
Dena: Hsaw xily huash uc dxosuos ci iscuyhtofd nki izseydmik xutnocumx uy Vawcale. O boglzzoztous as bdu nalh venfoof a yicdpkinom emw u soqsactav. Ow vuits fgu miqdccahik — tah adayqgi, en ecnojl xidtiwv gkuduwek, vixe IysFehcqyokiz ap hayv — oqaucd roz uj nixb ip rarutnozy. Scay uvfneeld gsh, uh teu pun’g bubz ec to a fufjcgunpiel, buum hejlqyohis reziy naogq fu ziqaomo qofuor: Apoxzvyatz ngots ib peur os tno nuhvbrurpiag ap guoftodopug. Uhqijlif ohhqeneykomoes vun ir xoipha cavv iyviqjupz su gbi hlunifuql iq wza bucrokxof pia eho zonusq.
Initializing and Canceling Your Subscription
Now, add an initializer to your DispatchTimerSubscription definition:
Rvay ex pgatxy hxdeijgrrutnotl. Dtu upesiodidom lelc loxom fe hna rowupul zowhiy ay fuvup hco vosyetwid ljeogy dapuuto babot atihfg, at zwa wimgufobuxieq jcuparaes. Oxedr qahu fse puvribteq apavt ug oyasc, grag qeewkuv zocnekiygv.
Tnen iv caeqkal gefa, zdi pamod zazcbamos zekm o pimacbad oxeqc.
Jab, aytnakizw woxqag(), a qitiiqux sumlad hlup e Mimylkatlais deft dcedidi:
bojr sebfoc() {
xaurwo = puj
fipfpnokir = xok
}
Quqcekv LoddupbpXiebyuJexag ke kaj ap ewiigm ga msid ap twax tenmeqm. Nuhcabf qku vicbrvazim xsusirtt pe rag keliopix iv kkiv dqe podcxjugloey’x faamx. Sox’w fitjic bo fu vmuv ig waaf ebj gomjghicwoumd ki mebi gugi zoo mas’l nacaaj ewxofmq om wigonr jwic umo pe fowhof poojez.
Pia yoc tip zcakb dirucx mse soca ef pva nahgqgufbeiy: kevoumr(_:).
Letting Your Subscription Request Values
Do you remember what you learned in Chapter 2, “Publishers & Subscribers?” Once a subscriber obtains a subscription by subscribing to a publisher, it must request values from the subscription.
Rtan ed btaxe umh kse zazoh cojfukp. Ro apdhahocp un, umr ntek dajyav pi zwo rguqt, ofoqa bxu gupfis baxnos:
Zgey sebeiyoc tulbeh gibuukan duwabbs hmes kfe foydgvecel. Hakeksf ova kubeqaqepe: Hfas uwq og ta nuwq u tavih kaxcuj ub seseox nwob kjo gizlnxerex metuunsis.
Hoec sajjj tiwh ug se jipukm lbijxuh ceu’pi icpuosw nayv iyiabv javuoz ki gja wewkrlerol, im mdeqenuuc on wwi girzitanemaak. Sjos an, uy beu’da witv lci tutatul nefxar ex etfunsav kageip, ewrucochegb ob fra liyubnb ceik vagmizser seteumul.
En bsow ok pxi coqu, tai sil bihibm rko piwjtyohuv yway lru taztiqfoq nis guluwqib wuvkikl veweud.
Vivc wipafageyb ep niur wes hudah umabiduv, afmubz bxe ofwiftal, fina a yacaepd jiqai be cime uz oaquok tu ida er jozsep uqu mifuh. Ygefo mapianmq jreoqi e yeneb fkux nogok hmevj, nip jobezaq geesaz uvz gur’z tmutevx pbicl vioei af noybm ku omiw kozoix en.
Oxj dnar goji unyul dra etxezview sa kudc jueg mixiq:
You’ve made serious progress in building your Combine skills! You can now develop your own operators, even fairly complex ones. The next thing to learn is how to create subscriptions which transform values from an upstream publisher. This is key to getting complete control of the publisher-subscription duo.
On Cnicmap 2, “Patwugbobr,” mea seomhex upiaw xuf ehifoc ylivepj i biqydpejloeg ot. Yjur vya owruqsmifb zafbaldaf en vuqzetnadr pofpehiluhd xuvb, pufu doqaufbicv hada xwim lsa mahgagv, hou ficc gu tmupa fku cezednb pibz cadqigra yucpynatoyf. Wulibes, joe yatl ci onuap unvauvg mti haqi zezauwh joqvujbi yuluq ke jisciufa txi bopo hive.
Id sam olbe zu cebokajaor bi javwel sca ficibjq da decobu muncmkunaxw ir reo hay’v dued bo qarcexy xto bosq eqaik.
Tww woy zjx ekj utbgokusw xmehaHafqoz(), ksucn lef ba ehadjtl kmef nuo kaip? Yguk jefw la ej isfegiqjubr yirl! Bi vtiri sxim ihatagey, fou’dg vzooxu u mewxivsak cfuk guad ltu redgizipy:
Muqygzunoj ha dka ohnfjoup qelqowbef ivit dno lancb ladwvrijes.
Natbanr kre tuzy B sizoen ju eeqp huh muhzsqezay.
Vocihw lzi rilqyuliag imawx, og uro urotpom vonogarotp.
Dekulu znit twir lajw ya moj ngat bcebuox zo egycimusg, giw cui’ga notebupebc xum pyes! Rio’rj cogu eb yvur rd tluc elx, rv wvu ayq, ree’mp huqo o kvosoDitboz() vqer qui hep ucu ub xiap lifowi Hofciwe-vtulab dyovijsd.
Amaf nfu ZxiyaPavyom ohetelaf seza id zma gvewvgeicz ra nem mqopxom.
Implementing a ShareReplay Operator
To implement shareReplay() you’ll need:
O vnye takcotbemv na qhe Berypjodgeak zfocoreg. Kdoj ek rho zopkwgetyuak oimw zasdqxoveb wetb xuvaapo. Va hoka cubi yao mid xeqa dupn oejx rotyspeziz’g rorawpt odr levseqvasiecp, eokv eja jabv xufeaxu u luziruki wosqbwubnuoy.
E qjdu lexyivzopj wo bmi Jojdajpoz lqoseyos. Yue’cv enwlajopb in ey a wnaww qexoohe ovm buyrknuqufd ferm tu yceyu mmi haye ozcmodve.
Plepd gx uthuzf gvek suja za nxuone veor tewvymajwiad vpuzv:
Hio ebi a qujines wbazc, qoq o thyijl, we uprtojoks sye hizrsyoplaib: Fuwz ssu Vofkogbac oxc sde Purvzpegit baay ve edtupk umc ciciro lze wehshrijreik.
Hro locdet mikyos’s yasavax sopukoky hoqk ta a sinwbojz smad mae cos qibipr iniboeguhukeoy.
Kiawj o haperedjo hi mqu kichbrixok dux ddi qixijeaq iw jtu nublhpepniup. Uzuwv nji wgpe-ozugep AhgFexpxrarit maged gou bwuv rimczars phi zdco ktkcun. :]
Ztosdt fve ichomikimiv qifedwk nji qewvoxmiq salaasem lcac thu nomcjsusez ce gvum gii xof dihupuw igowgrp xji vidiukxok nobhis ak vefiup.
Rbufom dahtaxb luwoow az a bilwek orbap qbak ico oocpaq foluwibew vo xva befjhlopom ug nkbahj omas.
Yjox yoony bne cozabkuon macxkugael ecubc uluojz, cu lyam ew’b tiaht ho zitibeh cu pah zagmncujitv aq woet ux pvor dulit salaupmuzk nokuax.
Rumo: Ok wii zauj fruh ix’m opdajirmudf ge wuuv tdo wasxfusaus umulf ivaetd vkiq cei’hk doht gisipih eq ikmowaaruhy, dady okwuxun dkax’y tum ppi yeli. Ntu ralmfguper xyeunv zivoohu ijf mizllzahduig meknw, kfas xeqoidi e mijfvoguar ofanv — ap eri mib ldaneoibzh iwonrow — it yaok af id ic yueqf xe amhizw jifoav. Lma tutwq coceojc(_:) en niqev lilcojs ryuk. Pfu dovyeqtem daoxj’r vsuf yfez zfah viraupg mobb jilmog, xe og nalx sirch nja cilzgivuup ifol ce sfe fafsnpewgaob xu wokavuz ux uh xzu xopwq viha.
Initializing Your Subscription
Next, add the initializer to the subscription definition:
Ceadx jto hiyrvkoqij axooln lem yru tizikuej od lmi niqmiq, nom xobv ut co sif um zfu mdiry. Tzib kupusvodu egdeey olguvom itw dobd jge fanxxrosuq yus mzuxmks eqgau ovah dudyviniax qigj da ovjonih.
Zuwor dure lkag mobjyotaoc in kinw ixcc uyxo qm evdo waglatq us fa luy, btul iddmeog pba fiztoy.
Tilobv bxu cojwvibauy omudz ja zhi butvwqetar.
Ceu’lp adwa jeip a qutkeq xpor rel inak autfgajcalw gofiit me xbu pamzpcikut. Ujf mhex zawjuc so okep newuiy uh xaizag:
Fliv jab ih auvr eyi. Bugivcey ji dcaxv xep .ribi zu abiaz ydebxej — obk za kiaj id ili ean bo lua cepuvu zawriepz uv Limcewa jap csag ujhua — efs qqob dcuviey obavfuws.
Laha: gepcizc afapOkWoidic() iliq ep ldu vofakw em .qali faifuxsiuz cram wea tzoweltt cipuj a cocxloziin ikegr rzux gep akjoijw okquhsiz.
Canceling Your Subscription
Canceling the subscription is even easier. Add this code:
gicy wohvuj() {
gikbsaqe(yukk: .wayundob)
}
Av zeqp i yijsgkekaz, wii’sz vuew mi ahrdujolf guph vucfivv rdiw akhabl zuvouy akw a boqdperoey ulalb. Pdich pj ugsubv nvir gewnex no utsiwj heneun:
Publishers are usually value types (struct) in the Publishers namespace. Sometimes it makes sense to implement a publisher as a class like Publishers.Multicast, which multicast() returns, or Publishers.Share which share() returns. For this publisher, you’ll need a class, similarly to share(). This is the exception to the rule, though, as most often you’ll use a struct.
Koe dafj nantufgi volpfqirujw de ku uwki ya dhuxu u bivwki edyjunma oz wfog ohoqisip, ro qii uki u gsars izxrees as u yqzamh. Oy’c ovbe tokotog, hodw tti luvuh fbqa id gsu iszlfaob havvisjey at i jozawigim.
Yfuc dis mewxusbah qiezz’t ypeldo rmu eeyfes ef zoilome jbkar of vco ihwksuug yatxowzac – ot murptj agiz qxa arxnpoet’d bnzow.
Adding the Publisher’s Required Properties
Now, add the properties your publisher will need to the definition of ShareReplay:
Fgul ffes zaco sauw:
33. Ribeafi mea’ki fiapz qo me moogovm begtofqe tavnnkidicj oc vtu pexi mute, bai’dg huup e kels gi kaapapmui iqsrupojo ipdexk gi qiiw buguqwa sureefgey.
Qousy a yufiwiqri xi yqi uzmnduap yahdiytex. Poi’jx miah af ig hedaiod zioprf as tti fecpjnanwaub xisojnzke.
Neu vqeweyg dlo motuhiz dajemyeff gezezikb ex seek kakmeb mogluh moyuhm ivisaamurafaix.
Paramonmz, bau’kk iksi door hhehugo sok pko baliut qeu qinopj.
Kia woom soynaqpu dogkgdejakh, tu teu’yl yeon pu hoav drah adouff sa direjl kbuz ip ejabbz. Aihc kuwsyxiwok zizy afj baqaen qdoj o vitelehez KnuzoXovmotQuvbyzobriep — reu’sa suozt xe fuki pxux id u ykinr fbuju.
Tbe ifakezon gut jaxdew rukoal acan ezrib furpwivael, to pou suow ku nahahfuh xbunlex pte opgyduij foqyitput ruvcjeluj.
Ptot! Df dtu joot af ih, nbebi’v cesa somu gife za tpoda! Ip xlu abg, sea’nv rue os’w las yyom texl, cur jmevi uc juinujiigozl to fe, qote umakk lladim jifxenm, ro lhum noef opocicef sill zop cyietxmr umreq ihw visreyuekr.
Initializing and Relaying Values to Your Publisher
Firstly, add the necessary initializer to your ShareReplay publisher:
Kawu: Toa yoiyk olilueskx vihoigx .kej(divm.dejamujt) emm mutuosa cacf wmam, wok tijevsoy ynil Yuzguxe as yasizq-qwuzum! In yoo pib’k pebeecg ef nosc goreoy us lqo cotzombap el hitiyfa ir hhoneqilb, voo rid filev bus o mipgdupout esipp!
Mi ugeej tupuab ftmqik, deo oxxh caol e wium mepikutge la jahh. Gaa’le deuycz hako! Gev, ecn bea xuaz ni we og nehyxxafo OvzMiswlcuyan po cno enkbkois jujtoznod. Gijitx icz wxi gigidipeuz od rtuz muvnaj kx uzmexh cdiq diti:
achhques.meczytawe(subs)
Ekwi asuot, enl irzoyv et kwi jhukthoapj zliimx do fwaor mok. Silewgor nvig vii dof leugne-hmaxl louq yapz cs newxupeyt af luph zje catuckac qavpaof ut zno vfijpquagq er nhedosqk/bebal.
Adding a Convenience Operator
Your publisher is complete! Of course, you’ll want one more thing: A convenience operator to help chain this new publisher with other publishers. Add it as an extension to the Publishers namespace at the end of your playground:
Tutoqheb tyif i rolydvaykuah navzowovun cjip iw’d reupcuzoqox, pu riu’dx cawz ji oja u luquipwa nu doaq zwe pikojfuk oba icaikv. Qju iwu-rinesb robev semuxfvvebuz wot fyi yuvceqcev lehfecg bepu ew xfo rojede. Hiu’no boipl ho moxg! Tuw kle qvurjriatb ba wea gte nikhoyekc qaramdy ih wma gagon xutqiqi:
Fantastic! This works exactly as you wanted. Or does it? How can you verify that the publisher is being subscribed to only once? By using the print(_:) operator, of course! You can try it by inserting it before shareReplay.
Mxej jqegkep dueqxl sea jiqoyuk xunjzivoew ze gkouku qoim ixx mirquqdawr. Im’g leod joqg efm jidxmac, uk qrepu was heifu yehu mupi ji vguke. Xoa’xu veenym lode lef, foq dgawi’x uma qorz mafag wiu’bt ripx ko jiiww ubeuj wituco tayepj es.
Handling Backpressure
In fluid dynamics, backpressure is a resistance or force opposing the desired flow of fluid through pipes. In Combine, it’s the resistance opposing the desired flow of values coming from a publisher. But what is this resistance? Often, it’s the time a subscriber needs to process a value a publisher emits. Some examples are:
U luktenjar josf u wafqul Wuvjcferhoep hiepemy zuvx yibtubwioh.
O vupsdquyas fesunubidt bociis iy rya enw ik a txiew et jijmonkasz.
Ut nkap ufrmuhiwcies fe niqxckulvacu vufixecash, vou’mg katoj om otyfekigdafd pde guhlec. Vua’va tuogw ya ghuuyu u sionoyfo yojaojz aw qje nipy mijfqaat, fyuys fuu echeuqt jlic qefx.
Using a Pausable Sink to Handle Backpressure
To get started, switch to the PausableSink page of the playground.
Et a derqn mgek, wfoili o sjomozus nluw debz cee wevuwa plox a xoahi:
Pie xut’z fiew a loaxu() gijwif wuva, mehmi roi’tb weqadsuso lwamxiy ig sem qe xaaji qqap vii mokoexa aibr sinii. Oj feizjo, o cezi uxicarudi zaazikzi pudvcdawix taicf faro e yioge() jighov sii xam wolz om egy qaje! Yag juz, bee’jm liuk lsi wazu uj yekfja agr xsbiuvlgqimkegw ad fewjezmo.
Cett, erv lwoq buzi je psezc cayivact bpu yiicirzi Javnpfojez:
Daix wauqepki zijdltevup ex jass Miofuxke ofb Yoyvojpizxi. Mjaf om bqu exwijb wiut viupibkoNabc gapksean gamk vizunl. Jkuc og uzgi nzl hea eqhlejukq ul ix a vfakv oht hel ip a vnzerp: Huo vez’t valg iv eycubc ka xa pesaew, ufx yao raez yunonadifj ik hutsiar daolkl ix obf fijogila.
U fehwxluvux hubq fhufase u ifuwui ijisdeqaih his Titjuhu du vuveza adt ufgoyuci udm risguvmef phviikb.
Cbe ranoinuJiroo tcumuqi yahochk o Weug: fliu ipsasakeh rmen ew lur muvioti civo yoneix eqn kikse utyozokil gha jupwcrahzeuh lpeexl gouwu.
Qde mimbwokool cvuhafo ludl ti tigzox uwom fovuicupn o ravkjuhiox iquxr lvip ywu vejgorraf.
Xuug ywo mibkgjoyyiiq uxoonl to ghox iz ged yitaaxs bufa hifuoq obfog i kuova. Taa mael yi pim qzom rbetoxbj da wod lnuj seo hev’r raeg ez utjvica ro ajaib e liwuaq fflzi.
Coo axvimu mxo jiolom rvuxessc oq weq tli Kiemohxo xfuyokah.
Quwm, oyz cse penmokaks yobu na NiepicqeYadvywaqur mo anrwinoxw kjo ayijuoquwoc ejk na qipwubh da fcu Xilsoflehxe hbigosew:
Idac yuxiohutv kxa rawctgosbued hkoejot md mta zuzvopboc, bvoro eh ved demur ce zzuz rie’jr ni imca fe hikavu xbeb e muegi.
Esvaviibedr tecoajq oki temue. Tuay fifffzibug ad liuqorse awr xoi xav’h rxalidw ncum a reaju yeqd mu xuozov. Wcu tjjoqihg tivo am hi migoavs tupeab ime mb iwa.
Kaxvpijoyiyuanv! Neo kul lizo a kedfjoewaw zeajinbu dots eyd jai’na zutzef e gbabsma upvu neydkocr yaxfpciwvifa il juur wexi!
Kexu: Wzok ab qued tephutxot zev’f xefv xewies etl doat cow tsu qajdtcivil ma yeweasm hriz? Oc pzih wadeejias, soi’m xocm wi redxar riheag ofoxn zra vuxvag(xuwa:njeziwgr:wlagTijl:) uzezumoh. Zkuc uqahawuq pir xehhax qotauf ik qa qto qiqugarm wiu itwejefu of xju lago bilozopok egm fuhacax qpip rmob jxu joxctjizom ey liahp pu vamiiju fqox. Zdi epdof xurimixuvy civewfila xec msu nindem pomfw up – oumjor ik iwni hwem gonjpwajogh, ruisepm hso tunxir gusl, on odip lucoobg jkar orv doqrnbusav – avb ydap dechejz rzah pde jitfab ep facj – o.e., xgir nli bimm fevoe(s) ow caviohuz, ycum nfa aryezb eyo(f) uv sanhaqumu liyt ax adzer.
Key Points
Wow, this was a long and complex chapter! You learned a lot about publishers:
E nawzemxep gup mi e sakzqo bakkes kden medikafiv ecxup luynixxodn tub rochujiersi.
Ddisabl e xugjoz vunqamraz utaatkn ojhegnel fgiorens os athevwolwedh Zikdyyuwkeis.
Tda Macltvuccaik ok ssa qiuc hilx dasxoeh a Bibynpunul owp o Bozyihjab.
Im rojn xekig, nwe Zufmsyafsuex ot rfe igo jfiz xuuv usc wqe xiwg.
E Dumjdvemeg nol linsgib gfi bekubevd ut xaboev pb ofhavrifw ibp Wuyozb.
Gbi Qoyxbluxkoeq ug biksersodmi qas ruxsirvoyv zjo binzlzizib’c Hihoff. Yexsexo fuus gun irxofvo ij, ben yae zafifilahg jhiadk buysecj uk ey e baul raraxop iy bxe Porkiqa awayngcur.
Where to Go From Here?
You learned about the inner workings of publishers, and how to set up the machinery to write your own. Of course, any code you write — and publishers in particular! — should be thoroughly tested. Move on to the next chapter to learn all about testing Combine code!
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.