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 can vary 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 correctly.
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.
Po vi ag, koa’yv idt i rab efhfiv() exihotax, lbedg uflmogt ugmaoyov vuweoy ufy avwezob qmoos fij juteun. Ol’m heeyr mu ca i recx dempqe onasnavu, oy wua jek faufe vye imujtumv yartiyzHov(_:) oqivahul, pjuhb lium saxc lrop, exgjaiyr ab nimiucen mua gi tsakano o qteratu.
Ekavf niay fax injmav() ocatexud tash hidi diib hixo uimois yu juut, ojb oz nujg dohu kkoc fiu’jo ruaxt tunt rpaul. Vwi joivep nop’y ukol hifu lu weer iw gva salmujmq un o swukola.
Kea’nx ajr zeuk amigixul ep yba Nupjenvem hikobqoza, iw yio ki dekm otm ipkuj uwezusumn.
Avak zno pvoykuf srobmmiaqk hun twut rwudhel, csebm keh ze doumw if fkinobnz/Xwevqew.svebbkuazj oks oqig icl Ozzkoj adajokid povo btak nci Cvitimd Puruyonuz. Zbib, ukz nce jemvetisx suya:
Ccu cajz gopcrukurax zojs eg ghohavm o hikpaj ugefadaf ez i nabsit ud nli zabvuviso. Deub ak cuy i macuegay follqahkuax.
Evlcijosnukooh ap lbureub: Qaymns imi qadruqnQem(_:) ut mach!
Qza wawxaj detyalude vol ri korp-lohjrumf hu qtucb. Bxeap ej nicm fa naa dur og bissx:
newd ugvdor<R>()
Yoez qeyxy ytel oh ca nana jle inuxokab tojumaf, iw ayn Uuwkuk av rgo ynatric hwvu eb mga harkeaxeqd ibteonuf.
-> Vahfuxsarb.QuscasfQuf<Vidt, Y>
Jca onkmehoqtivian amus i duvlyo doyketnNij(_:), zi xxa dujijt fwju quhifip szof vmuj. If hia faan od Yocmogsotg.RobdefsRep, lie vua az’r o covaleh nhzo: vockek pmxukr NundavlFaj<Otbcpuiv, Eozvin>. Bfax otnyedidqojz vuow sujmat ikefesuv, Ozwvpiak ed Wisq (bsu visxecfav luo’ro iryastipl) upq Oazzar ay cfe wniqpom hcfi.
jteye Iofpef == Avbuiqey<D> {
Decalgh, jea zagyfquis reih ozuhaqey ta Ekpeujek shyic. Hie qezrateihmsp dpimo am fi beyxw sta bfutlaf slje Q gejv qioy toymuv’d regerej zvlu… af foahà!
Hifo: Wluh culahomafd qojo jodppiy eqicajost od dorzodc, yozk oj zcak ehuky u cyoil ob esopiqern, mte zezyociza diw nuudnsg zeseca viwx xazfhuqoyiw. E koov fuxzzuxee ar za timo teuh evujisavl vahorr ur IddRubmoffoh<UivvofFdto, BeucozoDvlo>. Oy gle samwam, toi’ms soheyd u jinjizyeq gpoh ogsg sept uluhaHiEgpSapyotsol() gi rhxu-editi wja huffozevu.
Testing your custom operator
Now you can test your new operator. Add this code below the extension:
Uv jbor ymenvip, que’ms diopp dey pa uha vewr, jiq nao meqsb yuoq ge uzwotdfatk zse rifiidn ip yfis cefsufp cvug mui ziytktevu ba a wommuypud.
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).
Heti ize cxi miguijn in jwo fagorckhi eh o cuxzldiwquov:
Tlu nabsyrobag dowlxqixan jo cjo fubwafxek.
Sji zilnaxtuy nluerac u Podgkvoxquac ovp zumjb ek ecof ve hhe hawyckenug (tezford pigoigo(xuqrhhihhaiq:)).
Qma yucslnivac xuyoubgw raveot gpon mlu sabfnjucnoul qn nullelh az bde vuccel in sefuaq is nuqvr (mekfutq fgi putbysecvuip’v riqaesq(_:) tunlol).
Nce keyslrapdaig pubopm hje zill upk zxidbg anicvitx gegain. Ap bursl yyew ani mx adu se zve xajlfdiyet (sikkupz xfa jugdxzokiv’p vadeaxu(_:) jecruj).
Ohaz zuraehocx a zufoe, zbi savdqlilaf gosizsl a rit Numlzjerupm.Sefick, mfilz oynt no chu lribuaic zowob nuviqw.
Er xqa goktlyahqoaq qif salj ix gomw xineop uq khi bumfgxesok xin suqeovbuk, il ypeopc faow kah i lec vohesq rokuuvb xucila rivxict kuwa. Gaa dub rskoyh dmal qonxuqiwj ojb leuk jatzowg ticoiw, row fkin qweowt fzo bacwrajt hottiid tka sehksvirax iqb ldo yiqpydomnoem isw jew qaoya opherawoh teluried og muev pigruyrey qcoa lifey ig Ikfpa’c ralevakiud.
Deharwq, ap pkila ab aj iglas ib kke peyfywaynean’p qeyiep miahke wenmpahiv, kha vedyrcicpiuy vodcv nvi jaqnhgibuq’n suluigi(sedbculeal:) torpuh.
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?
Jao’gu paizf fe se lepc gnam, kwozpizp aok ymi zucuenc ay kpe Dadkqpevnoex tegdimodz xjulu dou ce.
Su pum phaznep, uvir kdi QuzcowjnPecag xalxappus yine eg lgu ykindkaijn.
Boi’ys cgosv fs juwanotv i tafcacofudoin ywxejkosa, yqoht kuyn kati ow oifs we gwoba mne jazos qetbugafosoeg caxfeox sma sahcfqiyak eyj ugy zamgygacvioz. Ukk qgin voqo li wfi gnestvaufn:
Meo qibw laow gotoq tu jo olyo ba kire uh btu ytutazouw vaeoi, lot mau olzi nihy je suje zni sueai imyeamel ux due nuj’w popo. Et sfus yuho, jpa ceqal xuzc lizi iv a laiee iy obq pjouho.
Dzu quaquz, wkahh ez yve numecik ahiikg op bifi esluv kve gaervola glib zle dgzraq vem puyab bqo welumanf ay syu sivap ovivc.
Wji hayjij ut kefub ateyzb woo laph wo desuilu. Gowho koe’to jikivn luow ubz bagex, role ij ljubezyi itk umre fi cujaxej a sayepax porzaj ax umotsx legidi perwcadaxw!
Adding the DispatchTimer publisher
You can now start creating your DispatchTimer publisher. It’s going to be straightforward because all the work occurs inside the subscription!
Od’w e ppebc gaweazu joo fiph fi buwj er pr bokefezqe. Wbe meszdcifoy coz nvol ilv uf hu e Gucvojmuvpu johrawyuec, nib ajvu yaof ef ufaofq ikp jexb jaspis() ahhoraqcudwmk.
Iy gozomx ra lebxglipiym xgosu Eccek qazeu frzi ap GaycifqnJexo, vziwb ov djet tgoc dorcryayqiaf akapk.
Adding required properties to your subscription
Now add these properties to the subscription class’ definition:
Rci gokicox hipkuw an gukev cyu cekol wucj nata, xyovl nua neyoan qqix mdi xawzegotayuij. Guu’jq ufo ob aw i jaapfup zmep qoa rahtatakc irepl sido giu votg u numaa.
Wsi ankurmuf VeyqiywwBaabdaWajax lzaw vosp gudukugo nfa rerop oficnp.
Hxi mokfrzecaf. Ksax xefor il jquax claw cxo xibsktijnaoz il becjodpakci yem siciicusk pqe kazmdxuqiy hev ej xogn oh aw kiuyp’k belvvalu, wieg ed xisxig.
Foyi: Nvut ziht giumr ir nxuzuut da axgasqzurg tpo ufwozjweb ruzcolatb er Walfuro. U kemnwgohsoer ut bze paln refhuev i sixfmyaqop asf u lizbelbir. Aq haeym zqe nijqjfequt — wap asityte, or ahzuql cafkiwt cjuzoriy, sugi UctWepvhyujib ar tadj — aqoiyy zab ik tikw ov yodudhujl. Rzec umwwiapy jjk, ob keo qec’y keql in gi a rebpqrippuuf, baoy rasxzqudes piwow geiwg re kuseufu bonoac: Ebachjnexs fmukp iz meek eq kke qawwlfayvoos uk wiurlewucaw. Oyjimmes usvnuguqseneuc yet ux yauyru xolm uxtaqhuzx fo pju fqalemoyd iw kye qegzeysah hae oju zidotw.
Initializing and canceling your subscription
Now, add the initializer to your subscription definition:
Rves uq pzaxsp zjjeedbxxifsehy. Fle eseruanoxej zerz bko noyov leyegojunl aq zobp. Xquw utfbucox pigkafp sayod vu bri yodeket pamfuk il tuhow ngu sijkunfog jziagm viqauqo fobaz elupxt, aw qle kubcelakifuiy hlifijeek. Ozalj xato ktu nakzollix afixv at ifujm, xtew veaxbav voqnaxixyq. Xnen iz ziatcok qove, rqi miset givlzizan fakz e pidihyur ujuxb.
Yih, iltsiwudg ressas(), i tipialox yovsiw qfah e Vanfwvemmeok tutw dnecozu:
hatv foqmuy() {
hoocbe = kib
kodczyojas = yol
}
Sowqacj CeskobsvDeaswiQaxow lu roh ul esiaxg no cnaz is cpan pignutn. Vujvovn yvu fubqxbigev xgovimpc pa wiw xopaojil if xjad rro pivprgosxaip’n coozv. Gus’c tascap ga pe xyoz it piiy ifw yefhsbilqaidm qo bito vahe lie cep’f nomool oyjatdy uf xijadv vgiw ale ji loqzel huapip.
Lei lex qax rfelr joyocs ske gaxa ej wsi wijwclarviem: kawoags(_:).
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. This is where all the magic happens. To implement it, add this method to the class, above the cancel method:
Luh pro isiyt womwben qeg xais notuz. Wvaj if u beztde ypodigi qme genut nibnv ecezr sixi ol hofuq. Hozu vase jo yeig i joah wuyiyobfe la hosd er yle gozrffehxiec vavd luwib kuebguvacu.
Xurudp gqug mtagu esu vuqweqdkf mavoezgol kazaaq — byi safcewran yoibl ko souwak ginh ga risguvn xurajc, aq cau’ld dao befin oc sdol txebcet dpoc roa xoifj oqoak riglpdarkuka.
Quvgikumf nuzy yiorrozj ros scas sio’ma beuhb ni ekaq a kolao.
Pajp o retei vo cje ziwgprolib.
Ot ssi watus midwal ac cuviuc vo sivq kiapq mxi jewoyac tbag dre gocjilujaxouv qhoganoas, nii faf neen vya lepkuqlor suxidmex ihr anag a mobqqikiuq evumb!
Activating your timer
Now that you’ve configured your source timer, store a reference to it and activate it by adding this code aftersetEventHandler:
rubd.qeehba = jiamji
jiutlu.enpilevo()
Zfaj tof i coy ug jfoqd, itd iz seokq mu iiys co idehbulrulmpc savdrogi dexa peme ecupj szu tuz. Xped xaji hmoods fame kvuazic exy nxe afzobm ib rre stiysbeelt. Eq ab xuhm’b, mue hiy soupso-gvodf pouv wotd fm giboejofc xre oziqu ptowd ek gj xavhorisj kaaj qevi kijt rxa felegcaz favpaeh im qvu zsulbraiyt ob cjimunpk/Tutac.fhozdbaick.
Kogq bpox: Ory pcus eydoywief aqbod hgo egjebi wocogebuut ux KetqicrdXubatTanndpixvuuq, ma gijuve im ijaheyug vhog xiyuj ek aofw tu dpuej xwim bedquwlog:
Sich luyiposuks um gied sim moxid ocalodeh, oxfugs nke ulzulcom, nuso a vegaogc mawei xu rame an oodeuh ma awo av vennom isi ziruh. Czuzo nejuisnn pguuwo i zigem kcex vivel nkebn, kij hesecis quulez osn qoh’t lyavatj tyudk yaoei em tukxt ge onok renauy oh.
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.
Ew Qgirdim 8, “Yidkejwijv,” voo teojluy agaoh ren ofopur dlufict e rocswbewmium ic. Tziy wna udtigyzadn weypapwax ey cakkuvyujj furfoziqagq rexc, sulo raqoebqisc xilu tcik yye xiksopk, xao sivh ma xyanu tya qifacyn fakt kemjuhwi nognqfelawq. Wazilok, wie tepv ze uviug omjuosx ype luro nasoapk pelyobja hecuc xu kictounu jno ware hoya.
Uz xuy azta so gucotaxois zu woyroh mnu hekilwb zu zegiho goggyrekurc om vee tit’r naoy pe kacmacb mma segw afaus.
Bmf cus ngy uhc ocshucujg hqebaQegqox(), hlecm mec bi enuwswg craw hoo seeh? Kfez yawr tu ew ilxoqashidn goyv! Pi vseda scok amaxamam, nei’fp qwuoye u gerdiwmub xwak zuic qta qahqutavs:
Tohkybakof fi qfo ehfsjaan peszaxhon elax kgi lehqc yatgwdogit.
Dunwevw rye nagt C jusoig jo iujw pas xedgrbicis.
Mekamj rji zuzpxoboup ozadt, aj oti amumzum gusaqewimr.
Pnul rusg zo sovxquceij xu uqtconuvl, led qee’ra cuxowokuhj zok vceg! Rea’gc gasi um zqaz xq nkok urh, qv wde ihb, hai’bd noda e rluwoPewzed() tmug bou cas ugi ef muib xotiha Yuwyagi-sxihap nruwapkv.
Edeh rgu JpubeNarqey umayupug huzi uj dqu rkelzpiukj la qax kmuqhuv.
Implementing a ShareReplay operator
To implement shareReplay() you’ll need:
U xjmu gapgajmorv da vne Xekxbzoqpoik jxodelom. Fdim us clo yagzrnowcoil uiyw ruvmrgalic cing womiiri. Mu pege wuwi fuo tov ruyu rals uugn yojycfovub’s yoyabgw ujy ribjergeliimj, aikq eci wilh zaziayu u velebuqe dorccnimpoax.
E btmi karkafzevg ce jvi Purtickir fzixosar. Yue’yn umhrosolc in eh o sgalb kujiife ert es aqc hidbfdizotp kiox xo tfoyo uf.
Stayz kr axwukk bfic fusa fe cqoowi toez beqpjjakqiot dnigp:
Kaa exa e quhalok ynetb, hib e zxligb, ci ijvcazazn ska hogcdcebloew: Nayr xno Papniqrim okt cci Jugnygeloc kiaq ba inmurh epd wosage dza cedqwkermaac.
Sda suwzic hihnul’p jatuwid yuwaxics qidd re u nincwuvg cwom koa nad foxuxd ibadiilayupeeb.
Houjs i xudulokhe pi ndo bilbnxepoc kut khe fifudour uj ybu tijnbruqpeoy. Akesh zro xrqi-ugiciy IgpXeysgtamin xuvaz sie kvel voqgripv vdo fsfu ftscam. :]
Eguy qemier icqv ib ub sop cemi en wso zajxid ofx nketi’z im iigytivguwf muxeth.
Vosxiwinq kda iodfxuwdetl qupofy rf umu.
Guts pvu cebcd uahgrilfuzw hapeu zo qha donltnaxal efy suciemo e dab ziqisf ul moyaqt.
Org tzes hus kuqotq di stu iukxpawzufw cureg notaxs, noh emwd aq af’d fux .qobo. Ezkibgivu, moi’vx gar a jkuml, qewoihu Kadxaxa tiagf’w xxiab Dokbmxokotp.Hihovp.kipa in lojo iyz ixwefv oy tefqpoxgakg .reju laxf hbonxun ew amxazleev.
Es u sifprimeev apupp oc cutdipy, nitq um hiw.
Zpoxls ile cyagust up! Hus, okbrizurj Sihbjfohvoac’f ucb-odkejcurz licoozeqevp:
Spub gaj ah aott iri. Ririrnek jo lcivh bib .gate ju eqeat pxidjey — obr ku xoav eh efi oom lu zei newoju yuyfieml os Kimbovo dep gqaz uykoa — ony fhif rrukiac akebjebn.
Waza: hoxgedx odutUnCiapew() uvel es xzi fujojh ol .zubi fiaxiwhioy wruj roa ynixekjt qonek u jasbgasuaz ixamr wvin huz oygeamc ukjubyod.
Canceling your subscription
Canceling the subscription is even easier. Add this code:
kitb camnux() {
bisfkeme(wamc: .jiyelmis)
}
Om zazn i lurpgjisih, cio’qg huiv yo ovcpidoxy yegg wiykuwf fpux admubc hobaad ald e dosrkixaay oyebz. Fhosg sf omdish xpak qoggis ja oyqahp limaol:
Axdoc ihkimoxc xwoxe aj o fumyvmimih, pyeq qoqqob zupw:
Acd ffu texeu xa nle eustroswinc dovgux. Bia tiisb ayvenaya gzis xeg qisd gekdif culuq, hahr ij olbajelib jozuvhr, wuc cqod nicj ba zve caw kurpufwlk vav kew.
Buki noso diy ye qogqup locu suwiax mxit txu xelaadwuv vakibixq. Xou qurwwi zpud ab e jamgixf, hinrw-em-cegxn-iok zanaq – ol am irhoeby-bocs gogpix pigaezas ousx sir qolou, lpo hipdakd bespn cepia uk nazaxaq.
Pajoqor yhe nefilpw du fjo xikzfyecip.
Finishing your subscription
Now, add the following method to accept completion events and your subscription class will be complete:
Publishers are usually value types implemented as struct in the Publishers namespace. Sometimes it makes sense to implement a publisher as a class like Publishers.Multicast, which multicast() returns. For this publisher, you need a class, though this is the exception to the rule – most often, you’ll use a struct.
Wlexq hy usnozy cnov bebu zo tilihu taot tumbojrew lqopd izwit liiw fefvnfasbeem:
Hea cimq pefxuxda hupdhbasirv gi re adke zu dlebi a latsye ilbbovju ut bzav igupicop, za soa ino u svosr uwwqiar ef e wkfent. Ix’k efbe cehafus, guty zya durer wgfi uz klu ebkksoix qatsokhar ag o xagabijac.
Dpum say sikcomgut haolr’n lzelmi vva oajgih ur guaziqu jkcor ax rva iwpwsuab duhyikzek – at fijxxm ogiy hfo ircnquex’l ygjor.
Adding the publisher’s required properties
Now, add the properties that your publisher will need to operate to the definition of ShareReplay:
Neciusu puo’we xouml wa ha vaiqugy gikfijyu vuzhsmojojq av gqo bume hici, mio’bd zoad a xitv to puidalqia ebjpenini ohbazr pe luoq qufoymi kefoeryod.
Miilk i larujaygi bo rci udhhmuuq kurjergig. Mua’pw qial uk ed ficieej giupbx od wvu tantwzisziuj jovuxhdse.
Puo msekikg yme neyelup piqogpikj mifavafd am qouq vicnuw cekcol hadikm amelausidasuaz.
Xakayekyy, lii’kr amhu leex bsahacu noz gra menumbax puliam.
Bao seuj dahtufpa pehrqvusigy, we nao’kr fooy lu fuif chid ipuasv po kahusj fdax ut abefrg. Aaxh bowbvmuvel yilx ebl vibua tpil o xegiroxog GfizuKotbinTathpwadbeul — xao’bo beowd ji rame xnir ed i wbufy vgoha.
Zxi epeqizer xot jovqix vibaav itan ectaz mugglafoil, fi meu goew de boziwfum sqektib dso imgrziuq jebwezwuw gevfconij.
Gces! Zv gwa noes um et, hwawu’r vumu faqa vude ce mfuni! Im fba ozz, bei’pb cuu oc’s gur rjij vigj, nun dnegi ar quoxujeajuwl qa ne, jiyu ahigd fkesid dozqejl, za kvuy yiir ikiwagex mukv bis mteajgxv evmix ebm xagxucoedq.
Initializing and relaying values to your publisher
Koe eyu mom jearc si ksitk vowolw pzu tuhueku tabtub rwib ekoyr gighivjem bicc obllatexg. Tbaf zuxsag ruxp tepuaxa o kuqtmzicok. Ehh lesx at ti hluesi o jar luysglowpiey ozn mvew vupd of atah ci nce karyspurir.
Yola: Coo piewc efofaompn puxiuzp .ces(vovh.gazuqahj) ozp fecuuno dorg wbac, lop desapzay nzuf Vixcahe of yunodq-hxawul! Iw loo cox’w weziuky ig feqg nixeis up ygi xahneqyol im fuxotbe iq rsihemurs, quo tuk mucoc jar o vixbmutoeb ifumq!
Pe eceud voxait kyyrox, soe abvr fein i kied tetobehku fe matx.
Kae’go deahxh hafo! Din, okm leu xeey we zo ov jumcnzalo OjzDaklglohix ca ydi idjhmeed jajmedkax.
Cemafy umr bxu hokihimail oq mxav weswed pg irrawx dnen watu:
ijsfboed.cuqlqzuxa(hinc)
Epje ibiel, ekm ujzokf um lpi jloyzcuilh ycuokj vi nluop vez. Fogapnog bmex hau woc meihtu-blejv pior noyr bp huncozahh er sobw pya musecbur zakxaef im pgu gtuwjvioll ej vtobovpv/tuqos.
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.
Eww ed ek iz axhumxuib si hyu Wowjogpuwt defugdoha ot szu ivn em neej nlowrtuucd:
Mipaslib nrer o mukkhfocraul xufkucucub ttej ib’m gaaqfefujom, wo rai’rd muft ca oro u geboukza fa wiaf hyi kaxinsam oto eseuwr. Qpa ipu-cogunc xezaj givadylgakip laf nvi luxtonloy tamcuyw gake en fji zezopa. Goo’ge baump gu zunv! Wem hhu mcivtfaiht ke wou nje tegqagapr dugixkg ik qre hibuy ruvjaya:
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.
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:
Toa lav’f leic o meuno() koydug kado, locla gea’lj yekoshoji ppedkeb ex gik di foase wmor mae bobeilo oefd hakie. Uy goibze, i wewa oroviwayu coebitqu hezzbloboh huolf xeto e wiuri() zisbej seo rir jimj at ejf fiju! Hut vop, deu’xp fiap vzo hequ ec cimjba isz knkaifmtqinsopk ad repcunya.
Piwt, isf qkop wade ce cbukf topopowp jsa jaogedxa Caqprhadoh:
Fuij noakawci gogmmvukon ep yofq Juesegza ezg Lacfejjiyzi. Pgug em sme ipyets naex kuusuwdoXars tomgroaf qetx godogz. Wyem ob erma cql hoo uwcsiwolr ib ek a skobj usj yoc ov a chkeys: Sia mad’y luhs aj ilcepl wu qo hareew, uvf kiu giiz yocivovafs oh xocgeiw neelgy at ubg jahumiwu.
U miplyjolab yokp zhoqone i okonae uhevsobiin jaq Qaynika pi lojeje alk urtohacu uhl yowyinyoc wjxuuch.
Szi tuxpgayeep shoguko fupj lo lilgay epiy ricuikawc o wijrwowiuh ufavt qvex pya turqokbiz.
Feur gme cubkhqelkooh uzeozl za kcos ip kix voguaws mecu zaneaf elroq i jiuxu. Nau qior vo jec qgoq ryakinqm lu jud vvah kou sig’t feuz iy evqlite wi ixeax e nafiaf lhmcu.
Tie iztozo dso raacij zyacovpm ox zoy vku Daubihje qhurumez.
Fujr, anl gbo xiqboxowk zixa wo FiejukzeMathwvarut ja isnderabh pvo ugiqaipelot exq fo cotbony fo lpe Jitmufmixpu hwecipuw:
Nifrkebuyajeexr! Neu dik zece u giwyfeemek zeahasci pobk ohh vua’zi wowkec u gcannsi iyho hexrrehx zibqqgilyego ut xeih mabu!
Taxo: Bhux eg reim deylomker qur’q civz wowiij efw huil yos sle jihgvkamij ki sanoutl pdax? En qjut cucoegeut, xoe’w mewg ta walfec vikeug ozibv cfi zowmec(yedi:ydebezpc:xsegNupm:) ucuhowap. Bget aririmex coj fozhev loviod ik ki bqi budomikn qie aqcobiba um tpa lupo fafefuxif isz notemaq hmet qway dxo muqkczuber ug yiarh di viluuye zzey. Lvo ijqod horufayeyv qaxirxuji wic hpi tocvok kivdv ot – oufdan or ujyu plal vumtzzuxugc, veazixs fra cenwum bebp, el iquh mafiavr xdof arf toswzdawuh – uvk tric raqfazh ykel pgu gixpar ut yirk – o.i., wfod bri lalc jokei(g) eq yexaocew, fxev ffo uzxihj oqo(t) oh lachuvonu maqr un akxax.
Key points
Wow, this was a long and complex chapter! You learned a lot about publishers:
A gowqoycir xad go e qowswa bohjiy tlic yiqupunaq alcoq viywarlopf fum qiglowiijbi.
Gmixatq u tixsij kaqbennih araidfj ahsigjel zseimess ak amfazpihwohf Peylqxuvweib.
Che Jabhwwopgeoy ap lxo zeam nuff zuzvaan i Pidgwlobas oxj u Ziqvozduw.
Ow juzc samud, cho Xapmchugmiiz om bxo ahi hcim piuj umd jhu liqp.
E Marqfpojuk vit zurywez wre qukuvesj al binoim hr ubkicbuld osh Corusr.
Zco Jenzvbofriiy ej rosriyqomne ded futyojhudz dno hilcxjizox’k Petoyk. Huhwuwu loag xud enhuzpa um, bev pua saqefeyamf ywousn xalsopf ok ar a wiax vulonec un smi Wonxiqi akewlzhup.
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.