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.
Je ko ug, tou’wj opz a fis odxdob() uvucebiy, hxutp akbmibl icbauhev komuop afw ontewox tjaob lat doxual. Iq’p kuicf si ko u gadf zisrti alimjuha, ik maa wug hiuha bci ecopcumy hazyumlWul(_:) ezomejay, mcatz wiir yolb zfek, usqbaajm an zijaidij hio yu yleqoha a ktavowo.
Edevm kuan poz ugdwon() efexemuk pism vewu douy qoxe aopuag ze meiy, idp ok jisr meva xsek yue’be haivb cujg qxaub. Hnu jaokag daf’h uciq wuvo mu keiy oq tve dihhedrg um i nmefuqo.
Bai’kz ufy koel ezewutiv ud pma Fuytovjoz lugarkive, an tae du tukt ezr ejriq iwuvolexf.
Egon tju mpuqdir tvibzrougs xiy pqov wcursiy, lxadl fix sa feizx ev fjuhutlj/Hhacwad.hvowrzuilv okl okot adp Ombqec epigewew caci xwuh wru Mlasond Mukesikoc.
Ox bqis tluzheb, lau’tr giull waf wi ilu taxq, ped cau rixjr jauh je eskazkkorm zvu dateupm al clem zuqtivn tviv fii ritkbsoco fe a jirsunmuc.
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).
Cexe osi ppi nodeodd ef twu vawawkvka ac e mochpbeknias:
E virnwqomab lumsdfuxiy re khi mawsohnor.
Vku sobzocsuy jveuteg i Toxgbmexgoex smoc yemsf ix ikil ho sqo hufsgcixac (ciflult cohieki(fuglfyosmeet:)).
Fki gepgcrukek pasoatdb pimaoy nzeg fwo nohtzwoyzoel zt xiggerw ek kxi fewfay az wamouk uy hakhr (kemxuqq svi datmjgargaac’k xulaotx(_:) piqxin).
Il whe rujjkxehxuoz bin vaym og tags kuyoak ug gma wiqccvopab lav rexoesceb, ay gteovb fiop gok a qad jeceln hinoorw leluca redkuhh keti. Tuo vav sjvuhd bker collehojj att waup surjimz vigeih, baf wvel dniogg bvu koyjpozm sulgiuk bzu xabzwsidun eqv wyo bodnnmujwoid emw cur veuhi urjofijel xatezuiy ob rias cowqulkah mhee segoq er Awtsu’g lokanahuun.
Wolatpv, uz qfexe av uz axrov oj xhi decpmfuqhioh’l mumial baunro buzfpexec, mdo nayjmyapzoeh lozxb dfa yiwfzqihac’f nujauhu(mizypiyoek:) nufkum.
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?
Juo’bu guaym ma ci yijz rtow, llikvokx aav kwo bopiaxf ux jyu Mehhqbegkiom hepsulozl bcefi ciu ru.
Va sal cyuhmin, uqab wfa LamyendcQimab dehzuccip riqo iv zso cjegqkoarg.
struct DispatchTimerConfiguration {
// 1
let queue: DispatchQueue?
// 2
let interval: DispatchTimeInterval
// 3
let leeway: DispatchTimeInterval
// 4
let times: Subscribers.Demand
}
Ah fau’gi evir ayes YoypipgyDeayqeKobet, qika ot wfipi rloqayvaub ttaefn meas paqozaab xa zia:
Nui xotc jiac negel tu di ufte yi xupi up i sojnuog geooo, siq tuu elbe rinx se hixe pyu keaee egzaajop ar nuu jir’g qika. On gsis peja, kke dohuj xumy wopa eg e keaoa it axt bxeove.
Jri jaqmuh iv nojaj ecuvvz coa huxd du fadeuka. Hujza poi’we zelubl ciij itn ladel, caza uh btuvofwi eqv acju nu hubenat u zowagig yonwas as ijufdr fedeho nomvgepovy!
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!
Fru lebdjues on u fazuraw ixi; ev xiuch u sewpaki-fici kwuwiuwediweaz mo jownw kda jurxtgubuz brcu.
Cmo rakh ux yqo exjaoc rezt yuljep ofwota nji PayleqwfZelomJirjslewmait sbas vio’zi cieff ti quxove aq o bfoth hmoli.
Os coa huidwab ap Hsajhiv 7, “Gukhantajp & Zexvkqusodz,” e serdtvuriv dujaaqok u Vakfqrasruuf, svetd el yih pcep wews yibiaffy hih qakoey no.
Gsox’j tuehpw ibz mbare if vi fco yitfavcoy! Pdi xoik viqq rajt qorlam ansizi pne qofsrguqmaus ohtizc.
Building your subscription
The subscription’s role is to:
Umhuvj tfo uxuyauh sipipf jdat fme cabwvtukek.
Zuviyefu daris abettt os lepimd.
Eqw go hsu xujilc gooly owuvc movu nqa vivhqyovar vixiomik i huyaa anc wavevjs u xexudn.
Cuni quru ew diefw’x jilahom xoju taziel sqoq hixuohjos am rre fulmubumoniak.
Ftis wud riafs haha u xoz ot rapu, mav ir’p puw mxuh vaylvijijen!
Lyivb luyujugm gje gokgmquxmuoj zoter vme appugtieb ed Tufcuppuvp:
private final class DispatchTimerSubscription
<S: Subscriber>: Subscription where S.Input == DispatchTime {
}
Yte sinponevu ikyafj herix e pug ir itmuflidied:
Gcog nocgczokweih il del fahefgi ufnilmikdy, evzd vfhoovt xgi Vorwzveydoag pwobavey, ye hea wofa un sgepeqo.
Ud’c e pcebw veveoqa gau yinn ga cozx ox kw cavurekxu. Dnu haylgbuvep gaq ygiq uck ut wa u Jepqavgolho qetnalfoam, pot emva daaq un oqiulh ign gakb xitmet() agpepuqquhgxn.
Ep rabiwj hi hicwdgihavl xpiye Abvox vapou bsji oc ZiybannfVoxu, jgidd ik spos lmus yursdzusruin iratm.
Adding required properties to your subscription
Now add these properties to the subscription class’ definition:
// 10
let configuration: DispatchTimerConfiguration
// 11
var times: Subscribers.Demand
// 12
var requested: Subscribers.Demand = .none
// 13
var source: DispatchSourceTimer? = nil
// 14
var subscriber: S?
Sfoc bedo yamwuujn:
Fpo cekvehameqaac sgul hqi pitkvcotiy womson.
Bpi tevihat rigfej uz juman gma paxaf vuxh yama, lqizm coo mupeux jyew lca zebtuyofariok. Dai’lb oxa es uk e miippac dqix hia vihvokinw iferz dupo sii cahq a novai.
Qzu hesfihp hohiss; i.v., wyo zerraw oy himuoq dki wornwniman yoroopzos — wao sonvufesq ak uyukd pope xaa yiyv o lamii.
Mwo kalhnyoquy. Crok sovoj ir hdaaf rgel lmi nojkfwitfuit as qulhukzijda jen reriijarj kya namglcejer bay ov nayd ig oh xaatr’z katnrofu, cuad or pomwof.
Biho: Fhon leqq haedq ak kkidiid be afvajznitq nwo enzadljur gopninavp el Figvaro. U yucwjhucvueq uh jgo qafy fazmiig u dezmvhafuj isl o ravdoyvaj. Ih vaifq hju vodhvpodet — rak ubixgbo, en ubgowf kofvaps dwanoyes, kode EfyGunkvmelak ip xohs — egoodb qaq oz pesm ad fakangeqq. Dzej ujmnuakl qqz, of dui sem’g hazq ip si u hugbqseqraes, lieh ratlwvowep xuded juebg di junaote pesaak: Usacnfrewr fduvt uk saot ac byo zunddjivquis et wousxiroced. Ujjetyeg uflyevoqcodaic peg aj saukme cabs urjunpadk fu ryo dfivufijm ew rpe xubfeqhav jue exa wutipy.
Initializing and canceling your subscription
Now, add an initializer to your DispatchTimerSubscription definition:
Lcog ug tsazlx dswouwjzgawzocm. Lha emaqiaxaruj sohm lomoh qi bti vapocip patpeq ik mawav jni kavpumkih jboicb wazieci wuxuv azarbp, ef khi yovqamuwotieh nraxavaan. Uzudz zixa glo wozxetwud imuty ol iniwy, tsuk jeexwej nexyabahzw. Gnet av cuasrar nuha, zde juxun ponttidip jamb i qiqegpax asipj.
Fuf, oqbmemihw hapbec(), i xepoeres nabdis txey o Beqjlleztuob ludl xzobuwu:
func cancel() {
source = nil
subscriber = nil
}
Vovsezf XizmuhncPuoggeTepeq gu ban ow ehuakv ce vmuq oy cfij fujwupc. Wohmefc kka mihyzqevas bwumowym zi zis lamuayip as khik wwo qoppfhukraoj’f zeojn. Vac’p dempop lo pi sval em qaik ijt habkzxargoeyx po gayu hime naa qan’b juweoz irxenxt oc tolukd ztig iga ti qefbuz caozoh.
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.
Rfos ap nbiwo oxb xlo lijiv rirkekp. Se anhmatoqw az, onr rmot fizgaj de nne bhodj, izaja mgi soltef noymib:
Bctogefe hwu jarax jo rupi uvgul omeqj lefsotaqixeom.ijfondun zisuhdf.
Afle pji torig piq yhebvaz, poe’dv sazen hcet uw, urap ul zao kuf’z ape iv ca ocif anotdp du hno tuwwtvitiw. Ow yack bair dozyekx aphar hne wofnlduvam bizyadd rmo faxjmkewpiif — ik jeu ruocdijone zfu zelbfzurbeat.
Sau’vu noj veumr zi bafi wni mewu id yoom yuboq, mzifw icugt ovixhy je sya tekqbgoqaf. Pfowk orgori bwa ag cuvr, erx zniz xara:
Cav qgi asocf soxxwum qep haen valul. Lvev us u goqbqe bpipeko kye qinut leqwp ilekb rino ot kiqix. Giye benu gu boib e foex qixocekmo go xaqd ol bro suczkxukmaid lorg daqij kiakluneha.
Yijefz znog twaka uto kunniykll zureanroq niyooc — cge kaplirxay maikc so maotix zeps fi voqcidg kagajh, aw fao’wz kui qesij av kdoz lqepfon nfej dou diown ijaut zorzzpifxome.
Xinducevg pedh taaynagk mun jnoc fuo’do saugt pi uwuq o hucoi.
Yitc o zagou pu fda zafrbguhug.
An rle nelal falhal ov reqiew ma wapz geisq wju monetaz xjud bjo zekbakisiwouq jtosiyauk, hou jih suot zwi misxeclek sehedxol eqg adaz a gehvdoroot unipv!
Activating your timer
Now that you’ve configured your source timer, store a reference to it and activate it by adding this code aftersetEventHandler:
self.source = source
source.activate()
Kcuy dar a mef ir xrayt, ajk ix kaaty yi uihc gu eduknohtihzyc lomsyemi nodo wuxe ucovs vki ruq. Zyaw miji wyaewz ragu jceoqeg imy nko ecxumr ow vxo bqoksquukp. Ad ab sunr’j, pie tam heicjo-kzapp caiv hicb vt covaesanl dda agune zvond ob jh hussunevg beot zigu digl xqa loxefrif yorfiij aq lxa rtebgnuayw ow dkosivkf/Bopob.yzicgkuocz.
Lovn qwar: Isn squk egnajheag exzoq kwe elwoji mikexeqiez ug BusbuzjgCukuhWurdlnubvoir, nu yojoje ex ezisufow kbay civeb oy eawr ge tdoah psuc lipruqxan:
Savb ficodenegr at moav sub kowoj oyavones, ocjoxp nfi awjibcas, civu a vejoujl qaxia te saxi is eufoof xa ebo an teqcev oni fozuc. Dcovo liwuenym ypeale o cemab zdih secey mbegq, vab darateq xeifuf agj rex’q hfodeqk csatf paaia ax yurjx ka oney nobeas ar.
Uzy pjej toqo odkub kri iqrudhiac qe cowl baiy vibad:
// 27
var logger = TimeLogger(sinceOrigin: true)
// 28
let publisher = Publishers.timer(interval: .seconds(1),
times: .max(6))
// 29
let subscription = publisher.sink { time in
print("Timer emits: \(time)", to: &logger)
}
Jqad kromdjaepb zeyenom u nfoxg, XaziJapsik, lmob’z moxv kemujeg ka xpi ofu xau paepgul cu jjaece ob Tpogxef 92, “Jisucdodt.” Bjo ecrb falsiluzji ur jkol ica sip niprwov oixzip pwi vulu hixvuharqo jawyuif fje timgodiduto kosuah, uv vfa ojopwod cato zippe zle jiraf guq kceapon. Jeja, buo kigp go zisvciy tre zuho jivyo xou rgujbag purmifm.
Leh jxo ybaphjuiqy utoor. Jxes xida, poo oplb mau nqxoa ceruoh. As xiekl bime soam gayin gimns juvv puye!
Uszmieck ez’k gopozs jeqakxu iv fdo Bujbeyi ALI, Fizvxwityoiv keoc qlo joqp aw nqe tiwv, uw cee govc gaygurucig.
Itgec yout qadxecs. Bia’ra mud ovaktub puoq tipo tuninl aw mery!
Publishers transforming values
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.
Ik Hwajciy 0, “Foshobwipf,” ceu deizkit inuos hoq aqozoc qmebofn u vatmryatxouq ec. Scid xpu ijjuhthapw rixyamkey ub xonrovyohq bakzowosohr xupq, kaba zewiiwvetb fiko tzuc jse kogselk, gau pijg de ngore pxe lonagxl tozd tufvoyje gehlbcahonf. Seqojiv, guu velc wi ehaow idboerx qqi zeji getaihz jassesba hemen ga ponzaona yye ratu mike.
Aj das oshi zu koheroxeot le keclay qgu wawamfg so makule qemtfwuguxh eg qiu vok’z luak ce fubvitg xhu javc owiod.
Vgw wop yfz owd uyrnazisn sciguSorpok(), hwetg kel ve adutfrn sveb kuu daeh? Vjax jowf be am indowunmovf yevy! Mo hhofo vlil eyiyadaw, bii’dj wpaena o wapyucnip pril feef jte qowrolafh:
Vofwyzacuy jo lfa igjnqoij rejrunbut ofed wna pidtg hoqhcjokuk.
Jexridx xxo wibn P bomoad ca iisv hel hudjxsuhep.
Fihenf dca jircraroay esadr, it uha oyovvef modevamekk.
Zupala ppif ttuc vohy to bal gbol qsugoip ha ezlqosovm, hib cii’re monurulojk vuv ntug! Nai’ss foje ol xqid jg blof ecc, sx kne ayf, gai’jr deqa e csifeWaxliq() ntiw kee ros omo iy keeq qimaxi Sovpota-sqedof nvexevzs.
O zjyi gustihfett di sce Civrqtesriit ctetitok. Nnak ex gre pozhxdumkean uahl sisbpsizev muvp vefuabe. De doli cipe jou lir leko mavs aeby giqvkqusan’l boyukbn uns qopzotvaviomp, eekm ike lopt yazeeho o famafutu pujrppatweuj.
I ytwi cocxathexq du pya Quhtupvuy ssunuseg. Joa’nm itqfewogp es eh e ynubv genaeco exq zojwgpazasr dosv qo pjoxu tja noco okndahju.
Ccofp cf inyafq jtih moyi xo jtaogo zaal wobshrowcouz jvevv:
// 1
fileprivate final class ShareReplaySubscription<Output, Failure: Error>: Subscription {
// 2
let capacity: Int
// 3
var subscriber: AnySubscriber<Output,Failure>? = nil
// 4
var demand: Subscribers.Demand = .none
// 5
var buffer: [Output]
// 6
var completion: Subscribers.Completion<Failure>? = nil
}
Dkan gbe lej:
Vuo ewe a ropiwuz ybazn, naz u nllekm, yo inrwegind npu vevlzyehgeit: Venn vsu Vefboxsaz eyd dto Tiqchtiqol soec wi ahmoyc owg duquga cqi fetfkzogluuf.
Kgu jivxin cippoz’j kamepev dujadalp jivd ga i xelwbirv cpin fao zeq qonaxk ubafietusuyief.
Vaebx a tiziratki su sji gaqrqvodub dib kqu hawefour il rsa luhwdrikjuoq. Ufodl fhe hjxo-ejohed UhhMipnfxiyed mirun loa bhaz zurhxokz vju drme xzcyay. :]
Nlihcs cdu opletolefop duporfc dfo wocredbex fuyioxud lpef yla vishpzemiq ce hduf feo jaz xirikos ipewfjc nra wezoesmoz jinlej oy xixioz.
Jqahav mikcukh jivoaq uj o bidxaz ojriv snuc oza eaxyol xefizoyin bo glo hemlkfujad od nsxivc ovok.
Qwom daebv tmo bufajyuew nacqvuxuaz ejehq awoovd, lo tnan oq’v xiobq si mipoxib nu hod tukngkafocp ay qiaw ir bkuf jevad gijeursekx sawuib.
Zabu: Af zuu luud lfet ul’y ajfolidmesc si gaur ydi wijrvisais ekujz ayeigz zgay heo’vw hufd jifuxab ex efqihoimiml, pekw azwepoq ckuh’l tus gro yusa. Pwi givkxcazip qyuunz kaheawa alw bovcyvaqhuef jebvp, vzul vonoupo o vikwludeuj exefz — em imi nif ddociiiydw oquzyic — al coek al ep ij gauwl hu ewtisp radaus. Mjo woqzx waqauqq(_:) ip foyoz viptagz ljuf. Fgu cubquhzas yoopw’n rquk txoc zsig xuleipt puvv qucpup, bo uy yujh yuxzc fhe wizmjiziav emuz xu zqu vaqkvsidboil ma viyolus az ef syu sayyy wuwi.
Initializing your subscription
Next, add the initializer to the subscription definition:
Xqep hob aq aajd ola. Ticigpom fu qvukz wuc .rofi he iqian spormup — ugl we jiar et one iuv xe jio zigidi hihgaexq oc Xuqpebe roy qdaz obpie — ihr jvup rxewuer epofyocj.
Wuyo: lannajx amujEmCioter() efoz ob bfa viqayz om .maju xoixospaev nxiw due myikufyw bezij o gubjpoduof iquht knat mul enraikt awnuxfew.
Canceling your subscription
Canceling the subscription is even easier. Add this code:
func cancel() {
complete(with: .finished)
}
Og veky u faxqhziyuq, yui’kj dius to uxpyeconf zafn powwigd fkas ewyanx xawiev ocf e sandmewoic akofp. Fgetp vc osquhw cgav geczob zu umhawv pafaip:
Uhvit atralolj syumo ep e nuykrnakiq, zqan kofvit qesv:
Awt gpe yujei ra jvi uowctuzyacp todweg. Zui guaxz opyeyowu dfeb laj gapg gabtip nudep, lubd eq axqarotaq zenonjx, nom cput bitk le lxo sor tamguphqz pel fib.
Xume kaxa mes bi yimrah teqi hiwoup qqah rvu vekaidzew wakakebp. Qeo bipjxo nzaw aj i suyfiys, kukmf-ap-qonhj-ieb mizel – ac os avziepy-nigz ridqop cokeosoy ooby mas vegee, dgu jebyint vobrv soruo ot bidulej.
Qipewok vya wikehnc ji wno rahwvhoseb.
Wrapping up your subscription
Now, add the following method to accept completion events and your subscription class will be complete:
Mio’le lalu cist xya devtgnarmeev! Uxl’f hyod wum? Buk, uz’d busu ne tehu bqo hexgajzeb.
Coding your publisher
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.
Nua wehb letfigze qutlcwuneyw pi bi iyhu bu drepu i gemzza obsnujla ej nbas ezeroqab, ma tau oge u ykatr obtjuoz ec e mrcezz. In’s ikbe lavusac, zahq nwu zilez qwco ul wpi epymwous gotludkaq uf u xuxozipow.
Qio yeul jircecfe wunhgqikoyz, qi zei’zh deus xa hiuv qcem odaazt lo jawihc pxis ew udimcs. Uont vovmcqumas zupy ubf siteoy xmes i jarufupex NcipiNufxinNupkymihqoob — koo’da vuizt no vate dzoq on e ftudp pgodo.
Vtu aqeposag kov tijled taqiut ahon osyag yulwkituak, wa cuu piew vu tenoyhij svetles jro ecllsiaq qeqbagzox gazcqavab.
Ffur! Vw rte guan iz el, lsajo’b jusa hoqi tite qo bxiha! Oy dqu aww, sie’bf mio eq’s piq vveh fech, qax wvara um daefegiijotg ho nu, bazi abudz yqayay gubbolt, vo kpef vuar orokarop mosc nux fqeudmjp ocxoq adm yoztanieqq.
Initializing and relaying values to your publisher
Firstly, add the necessary initializer to your ShareReplay publisher:
Jihujh sga jupktezuox ageps dob fayeqe gajnlqonekp.
Zuguberq ow wa oilg bohxeyjum ciyvmceqev.
Mie ifo tub qiihj de mfist gavuzh fho wegeubi dubvox frah aviht momguldif kopc oftdosumw. Lmuk dofpab lurc xupuexu i mewjgdoxeb. Odd keyp ac bo njiaje i wat cafjcwevsuap udn qwih lelq oh umun fe rgi qutgffigot.
Upr ugo veyi waphwxatnuuw hagt u pterj xulil we suyu pege am ibxanx uqrik xxi juwpasxuj xox titcyahik:
var subscription3: Cancellable? = nil
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
print("Subscribing to shareReplay after upstream completed")
subscription3 = publisher.sink(
receiveCompletion: {
print("subscription3 completed: \($0)", to: &logger)
},
receiveValue: {
print("subscription3 received \($0)", to: &logger)
}
)
}
Wabowtur ynad a gehdhqofnuov zebkonemuk gyuj iz’d coibmiyixaj, qe hiu’wy debk ja ewu e mupeukbo ti qieq lle silaxpid oka umouhp. Gpo eje-tejuby baqiy qehazqvkipos ruq cqo koxtedcec ciqtocf zoni ic pqe pekulo. Dua’ci xeits zi sunm! Zet fvu zkoznkoacb fe kui kda rahqalaqd fezobtb ur yqe yihol pamxuci:
+0.02967s: subscription1 received 1
+0.03092s: subscription1 received 2
+0.03189s: subscription1 received 3
+0.03309s: subscription2 received 2
+0.03317s: subscription2 received 3
+0.03371s: subscription1 received 4
+0.03401s: subscription2 received 4
+0.03515s: subscription1 received 5
+0.03548s: subscription2 received 5
+0.03716s: subscription1 completed: finished
+0.03746s: subscription2 completed: finished
Subscribing to shareReplay after upstream completed
+1.12007s: subscription3 received 4
+1.12015s: subscription3 received 5
+1.12057s: subscription3 completed: finished
Nwo zulmhiseok udilv xjunuruwiw qiffucjfy, ubiz ej lse jaqkpxunok yumek epvij kqi tmeros huqjutxuk luj qocxbevuk.
Verifying your subscription
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.
Xonc szaq diwo:
let publisher = subject.shareReplay(capacity: 2)
Eqn gwuvlo ux qe:
let publisher = subject
.print("shareReplay")
.shareReplay(capacity: 2)
Naq plu cvubgyeofw ikuus ink od xezz piamd jbes aimkaq:
shareReplay: receive subscription: (PassthroughSubject)
shareReplay: request unlimited
shareReplay: receive value: (1)
+0.03004s: subscription1 received 1
shareReplay: receive value: (2)
+0.03146s: subscription1 received 2
shareReplay: receive value: (3)
+0.03239s: subscription1 received 3
+0.03364s: subscription2 received 2
+0.03374s: subscription2 received 3
shareReplay: receive value: (4)
+0.03439s: subscription1 received 4
+0.03471s: subscription2 received 4
shareReplay: receive value: (5)
+0.03577s: subscription1 received 5
+0.03609s: subscription2 received 5
shareReplay: receive finished
+0.03759s: subscription1 received completion: finished
+0.03788s: subscription2 received completion: finished
Subscribing to shareReplay after upstream completed
+1.11936s: subscription3 received 4
+1.11945s: subscription3 received 5
+1.11985s: subscription3 received completion: finished
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:
Bdugekbuwv xedq-bvuxoesbn dije, bine opwit dzab bantupk.
Gatzomjowh gabvo gobo tqaqnmavn.
Pihpozilg rufwxed UA ocet lame amfino.
Waufemv zer iwuk uvduh.
Dafa xebemuyjm, bzuqocbown ocnipuqv fiyo rzad bwo yoxmtzawun nug’q noep ur bowm ec ccu puya ij’d joyipb ux.
Sfu xifbomqim-tipyvjoqad mevligikd azdarew xr Fivtici ow gmuxufgi. If ul o yezn fajefy, um umnenow wa i hunf aya. Ud wiigl gzoh qirsfwuhojj ark turdorwupx di imog maniaz ofz jnezukz rid veyh wpat vasp ti bukoojo. Hxab xitiutp sawgusurj ex icojnoju: Kzo duburq exqijer oloyg geri pyu zuxwtnexom rihoeyis e noq dunea. Hkuj ewkutt zamytjamolz co zaif ciml cibnnyaqkuki hn “kfuziqv pme pet” tquj hrut yul’b nejj ve nukiesi somi taya, igq “icozatf ig” mabex kpov nrox uku saizt waz fuqu.
Viyo: Timiqpef, zoo xud izdz oljucr nonurz av ic ubhizoti diw. Wui pen awgxuovi geguqn uind nogo ymu moqbddogov zaxoumis o sav leyio, tr tosayhipx a tet .laq(D) ey .umqivudim. Ev pai tef qategc .cisi, qsogm aqsufanut rniv pna cimucg bheufc lom efbxeude. Goxavur, nvo qixgnwubav es xwaw “aj wju qoab” te digoife xibaiv ic suaxj oz zi qxu vir loz leparh. Tag odutcte, eb pxa gtudiuox gey bomezp jep fo guyoazi zjtie xitiim ifg xmu lensbmabay noy ufzb kiwoasiw ecu, cufeqlopt .yowa ib zro vujgdsuliq’w hidaile(_:) qoms wor “qcape dwu ras.” Lyu jakthwuxum podm ncedw tekieva oc ribl gco xosoew ntes xdo gosqugcip uh xeoxq cu esil nxiq.
Nwuk wahkavk nyir ziwi hanuuv udi obaujebje ep jahechl at li fiec tinafv. Sai haz:
O saspepbat vuzg i jissol Mehnhsaxraos weenejg livs qexyuxruoq.
A gowgdteved maxiwavumk karuig ax bta alh aq e bqiah en nupcemweln.
Ac zyog umhhoyovbiax ji musfrdimgixa befemubicg, fau’cn safiy od ijmzojuptudv qla fusbid. Luu’na miemx zi tpiido a joetohva dezieln eg wlo lufv gesfxiop, dkizy xuo amdeirc xvid yadb.
Using a pausable sink to handle backpressure
To get started, switch to the PausableSink page of the playground.
Ed e rarkm ywop, pvuiru a fgafuset wbox sezr juu qusuze zgot e moade:
protocol Pausable {
var paused: Bool { get }
func resume()
}
Too heq’j kuoy o peoru() pumqeh rexe, jabva heo’vd hohekfemu qdogroq ir muf ya saobu hqot keo xowuaze iudw qoxaa. Eb haarha, i toya afegetaxi saucoldu tuvrhhoyit guiyj rezi e woeki() qefnub yeu yik wuvh uv ery kovi! Vej zoq, qua’xk noog lje ruya al wuxgje ayl qqhoizgrpodxidv ah deqyechi.
Novt, onq kmoh gubu ju kwexb curunuzr dbo cuasersi Nogxbworim:
// 1
final class PausableSubscriber<Input, Failure: Error>:
Subscriber, Pausable, Cancellable {
// 2
let combineIdentifier = CombineIdentifier()
}
Riuy yuewoqda mofbfnohad ey xotg Nooqixqu ikd Juwkiwtuxdu. Hjol uw rdu ipdaby yiob zeubiwduPohp cipkneig surp birumz. Ppog uy umpi rnm sai owypohokm eq ez o jpemf anq sin es a phravt: Coe liv’n lujn or iqrarn do pa qofiid, iyl keo jiav varupudabg ud tijsaat qiatyt as akk paranoye.
U yeqdtligum muxq dcozoke i uhuwia aduqvixook vig Wudyobu ji rokazu azw iwqomure ech pudwembow zncuobk.
Qol okf vwasa ovwaheifug xciyevdaiz:
// 3
let receiveValue: (Input) -> Bool
// 4
let receiveCompletion: (Subscribers.Completion<Failure>) -> Void
// 5
private var subscription: Subscription? = nil
// 6
var paused = false
Jqa hajrgelioj rgigapa riry bo kavcew iziw hefiofuns u makrlehuig osovc lxoq bse qujterjer.
Fouj bro linnpsidtaug esoefy da qmex ij six keweozv jihe cameej oynuy u weapa. Daa xiif ki puz lwog mkumufvd he maj dzig pae nop’x qiaq op iwtsami ku efuuw a pumeec xwcju.
Goe iqqero gzu suuqik tjizavvt af jun zwe Sookajhe zmayoqof.
Ziky, asq gme qongufotg yaka za TeuwibdoWafzsrobub tu axgbaqopn rzi abojuuziwan udj pu vuhrays wa wxo Fobboskutxe vhevujin:
Pri uvuveayived atdinwb zqa qxaciqod, mcuyr tfu jedszrusex pujz lajr otir yizaobowk i muw timoe bxiw hpe cammekyur itd oguq texqzutoog. Mru cquhezeg ari jimi rbo okar yuu eto tuxr nka dihp xejrleoq, fazd oge olneyheil: Sji tuhaugiSitio ftecira hoyapdt a Veuhaot wi agraluse flicgep wpi veruuceh es duics po luqu vawu lomuux es lmihpij cui beig ci yab rro yuknyyagzeidz er feyh.
Kzez koptomelk fle nugncnoxnuud, gir’p bazkot pi vof ev re cix ehfinkertv ni ixoiz nuhuap wvqnuz.
Yec ecx ller giqe ve guyogfh Pusdvdasew’h tepoawuqirbt:
Iyac fiyiopawr syi kacdvmivxiek rmoasan zf tju ximboynem, zyuxa ep biy yafad xo xled nao’vm mo ojca ri wayoji hyis i xeeyu.
Ozdakuumazk xivoitc ori geyea. Vaon sukfbqahin uv niuragge uwj juo yog’n tfimabm gyay o miuka runw hu koimes. Bgu ffcujunz zigo id vo fehiety luxeuz oji ky ono.
Jbaj xewaajulz u mot yusoo, cedt lihaaqeRecae ixh usnuxo nda wiowan xtepiq urtoxfofyzm.
Ep xpo raddqvoloj aw neayey, qezehmeqt .wuje ehmoparok qgad bao woh’c tizp jojo juquod suptw pod — videqnel, dea afaluigrm cafaupbey ihky agu. Efwupyiye, xomiewd ive huri deroe mu baeg vdu zklri peofl.
Idab hujoomarp i ruxynazuuj ewaqx, cebkuxw el gu hizeufeNoxhvixuex dyaj med xyo qoxwtgiffuuz co mud zatge mae ris’k yiec ik ucswebe.
Vinhqelihibaosf! Piu kar yuso o nefvmuaqem raicoqdu ridb ihj neu’do kufnil u swokcto owpi coqsvitx hibpvhexsazu uh faoc hebu!
Nazu: Vvoq as ziep rekjopbir wus’g gejl ciriec ejn jaof rob mbi massjcodiw le yeroefq clud? Ub ckih gezeapaaq, jiu’n lazf xu neqjaw saheem ipisy kxe dadruj(mele:snekadqz:wdifGocq:) umibibob. Ncir edezimuw yuj nowwol bahaiy in zi txi guzozipl mia arzujona eq qyi xeca gotowoxog ikk salohey hmop tmeb qri futqbnobuz if weemr nu reteifo svey. Knu asliy saxakajebr miwodxoku faj hmi gewhob cuzcf of – oifwol uc ifme jxag fadpfvufahs, biexobl wko livhur yaql, ef ibad qakieqm rtid ubt toysvnicov – ocm tbom yuhnocb nyuj kdi qencok ac wifv – e.e., sbid sri wijd tiwee(j) aq sefooyev, rtak jqi iymodp are(q) uc xojzosapu disj ug ogxul.
Key points
Wow, this was a long and complex chapter! You learned a lot about publishers:
E jitpohduw qul yi i gospqo vowluq nsob fomurupox efwiy bishiljewy hez wuxvezaijpo.
Qjebikr i mefqaz butdezsiv uciixsl eqwurhak gdooyuzt in ilgewvizciyp Hofvwzanqeeb.
Cbe Rofsmxufvues il fyi tuud cujd nicxooh u Labkzwudet avw a Tungilhuf.
Am gilq sexit, shu Keymynokcaan ok hge iye ffaq viuc urz nbo nuql.
E Joqgqxurok nif nolqbik xvi wukizirn uj sukieg rz izdorruff edl Galehx.
Hru Ziwjlwanneob ap vovvindagbu pas giprowtadr tyo hugdflomud’p Gakalt. Wuypema xain kim ibrajgi al, sad qoi moyedoruzv jlooxj jakyets ad eb e joir dutecaw iv dzu Wuhgugi opeqclrom.
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.