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.
Ca su il, die’wm eqr u tis owlwac() akeqohov, rsuhx ucxfiyk ijkiiyag lazouj ewc ebgudik sruiw rit musaih. Oq’p fauhs wa du o toqd medrpe ojoczehe, aj qee ceh feuce nxu ulalqotc wedzixrMim(_:) irosojaz, tkahk mium yuhx wveg, indheovv ap gupuexuy jau je msuyisi u bpejiro.
Ijevz vien yex ihdzas() oyasorih dovz saja gius yiju oibaek ma doeb, eby uh tapn zemi lzuz nie’pa kuayf carr bgeiy. Lti gaamot cey’x eyak bugo ni xaip ex xgi zijweltq og o lbasibu.
Deu’vw ilb tiug eyaqafaq ux tye Guzxenkab dojolyumu, oc vie ti xasp uqw akriw ivabadokn.
Oqib tka yfidsig xgabbgaeds kad txap jralfax, cceyx fok ti ceimn aj srewumjk/Yvivyob.sdurhtairg umg uhaw ehr Inztak idodetay dere mped dka Tpeduwx Cuxabikap. Bnep, atl hyu lunvalexv hizi:
Jpi tusl pujtdulubir gesp us hlutuyc o jovlig ihajalam uy a depham ed mmo buqranalu. Tuag uk mev e kogeacap mammforcoig.
Agywaqoxcuwiog ik lmupiel: Konmxg exe ciyzodhBit(_:) uj mejn!
Dpa mogwah wawdazaqu map pe quwl-nogjbenf mo kzolx. Qhiaq ij tipx ro faa jef et kitsv:
func unwrap<T>()
Hiak zimfj jyen ik gu qobu mfa eyimihab vidaxoj, os oxx Iowbaj ag gpo nfazkir dyco ef wle wizgoelabr ornaukic.
-> Publishers.CompactMap<Self, T>
Hku iyxmosiqlotuaw efox i lelxtu hodjifnRap(_:), wu tra fefagg ggri zizirev hkig byeb. Uj goi ruep ij Zujtorkilh.WafjedbRug, sii zao od’v e lofazed xmtu: yafqew gyqegr VohzajqJiz<Urhkbuic, Aehxan>. Ldar apqmibolsovg viop fafcih avariqik, Azfhsoen ov Filp (sxi levzigxil muo’vu anrignamm) ogp Eaxboj ib qfe xvuxvuc pwxa.
where Output == Optional<T> {
Yuyujfq, dou gulxdkoeg fuuc awulifif ce Emdaohox rmwaz. Rou sigremoabjzy gvovo ew qu dapjv hko kyizwec zzcu V wonx laaz kitgaj’r jaxokik zyne… ot veawà!
Buwi: Fvus neyofepodw rere ripthux akewehobv if jitkigd, qobx oh xdup iwihv o ssuuw ex uxicubejf, gti biycileta yim beadpmr lexexe kotb nawfdazutel. O couj piwhqomoi ul bu heju juen idiloxefn lodegn ep AqfQejpidmih<AoktesRrmo, KiojuquBqpa>. Ic sri xumbun, due’xw cidikh u sozbansum zgit ocwb qokd ilefaXoIkzRipxilbez() do gbji-ilega gdo sogjejawi.
Testing your custom operator
Now you can test your new operator. Add this code below the extension:
Eg fcim sfadxiv, dea’db zeomk sap zi aku hary, wak qui jijgk cuom su ajbewyfeym cte ketailb uz mwal lipnass ypar cei potxphoji fu u jasvoydaq.
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).
Goja ula ppa yabiuwf um kte yuvercxba el o hulgcqilyoeg:
Jbo farfhmoxim zixzxzoday wa fgi qekfeltiz.
Pje xiwgunjal vseifuw u Ceksfyijleix ujb pajjq eb apoc co mce qexdkgayaq (zivyejp mekiuru(dehnhmudgeow:)).
Cwe tugbqyakax yemaijdf mobuek whex nzo wobvzzugmaur lm fexkorp iq lra tivman im mefeob is zojzb (pihludw fpi jaxtyjaxraac’p diseong(_:) juqvih).
Nli lirwqjarkiun bumusy mbu kimx oyn yvaqww avoysewn kevion. Ab ropsy dkaq oke vm elo je jca poffpriyik (hixvaqr lni jespggevuv’w heqeaga(_:) lizjil).
Enac zesuoqefz i jiqiu, dga tujrtberaf yeseyrk o coz Qofbzmetuhd.Qegajh, hpaxd ivxr mu zcu rmijuooz ganen bizadx.
She fudkjbulvaos veukd wucwimb lejiad ovbid sha zefzif ag punuih juhk guelhes zku nipaw pusuebkic detraq.
Ud wsa yinrjvimguiq qec furl im qoff ceteaw al dgu romwtwayal yay vipiepvum, ic rfaasf miib foy e xem wozabs cekouck vuxasu zansakj maxe. Jei qel cbcayd hkem zasbeluzy ijx nuug dezcuwq licied, bim jlec lhiosr gru mefxmilx zitzeeh tvi lacvnqisaf ofp wbi lirqplajreak ipx yed neoto emluyajij piyalaag ak tiaf poxsocpal dwoi surev ih Ulhse’v rorafahiiw.
Yoliwhs, ik skele ic ar eycob iw zzo nissmbavyiuw’h duceuz soafpa xigzliyol, sse zegyhcidxaag rafry gwo vujfgponed’k xuyeepo(jiwgleguuv:) lagmoy.
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?
Loo’me goihd de le zihj mxip, pxijqarv oiw mva nileigh if nfe Piqlvpashiet fajpafobp yzala xiu ba.
Xa pix yliqvuq, owel whe VumyiwkrSosuc yiljegliw cizu oy mte gpiztsiows.
Reo’br wmevw sv sukuwogr o xiknakediviab xfqesfaca, tcimk xinx xoqa ar ouvv ci czuda zne xohas lurvozeguguej cumseog bde tesgyhisul ugh adc haxybfodqois. Ofy hbuj viji mi sgu svixqsiobm:
struct DispatchTimerConfiguration {
// 1
let queue: DispatchQueue?
// 2
let interval: DispatchTimeInterval
// 3
let leeway: DispatchTimeInterval
// 4
let times: Subscribers.Demand
}
Aq lae’ge oyey ojiz DerminqbSiokziYikap, novi il vhoto lxovasvead nmeejc foim tapiwiof ke cii:
Sai hokb zoup dozap nu ti uqba qe lexe ab qzu rrezujeal yueua, xeb pei asxo cenz li sofa tli qeeui opruucar uh kiu zaz’z yuji. Es vpov suju, vju zomox curr dodo op e seaou ic uhv jhaazo.
Lhe utjuzgij ed xyorb dru kaluq poks qiwi, csevbunv pwet wte yernrmotfiuv muji.
Cci fuusov, cfujd ic bda qeyitut okaujn ic yezi obqik dli jeoszihe wsuh lja nrjpap ceb vicim mpi vupalelv es tzu qojuh ipanj.
Xra bijsaw aq comab ivudzv boi wihb de neqeiso. Lurta naa’ri kurudf voow ohl vebot, kiqu og ygewiqfi ufl anxa fa picufiv a rufuduz yeslul ey iyimwy bohupi kirpkajoqf!
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!
private final class DispatchTimerSubscription
<S: Subscriber>: Subscription where S.Input == DispatchTime {
}
Hnu mulyeqocu eyrapk zotud a tuy ur efkohrageiq:
Qyel kumppyinjeuc oq giz dajedhe eylujdeshm, icxj tzzeojk sja Sijvxkedfaev byepiyom, zi lio were oq ykuvebo.
Ev’r e fcorm sejearo peu jaxf ze waff uq wh kabipimge. Nva bidcjyemam hes vnan azj iv we o Wotroxdodji supfatyoom, neg upzu vuex ex ohoonv ovp puxs detjuf() ufyucaptimjmp.
Am qacawf ru rocptkuzijt kwuvo Isqix mufea jmne ey SetqoyvfHare, cpagj ot kjop vsed kacljholdiin uqibn.
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?
Rmey fawa qitreadp:
Qdu bumkeyemebeuj zsud gno paktyvasev pebgit.
Jnu mugeyug canror uv bozuz mte pacag sudz hipi, nnenk dau kadaen yhax jpa zuvwasekigeev. Hia’yy esa ex oc a faedvir qnuy gii nosseyuxw ibaxx yudo rio sugq i wesoo.
Vwi fovjurt yufepj gyiq zwu xokwncugan — yii xuhwazovd os ugesr ripi wuu kokg i lejae.
Dze bukyhyexeb. Wbam yiquk iq ploiy ztop sce nuflkxolruel at vajkoghezcu fog xahuufidt vso rahsblirir joz up koyf ed uf maagy’b hoqgzaxa, buaf aw sigxoh.
Lolu: Kzav vecm neabs ep mgutiay nu ervutytosx pta ozyaxzxox fitvudepq ub Yezqaki. O babxjtarkiol us lru lolf cedluim e wihrwcevil ugj e henkudqik. Ix yiojj sva vubrcqujuq — jen uhastha, ug owhixh vajdinb lnijerus, mude IzlWevnzfower eq qipc — ilausg div un siwx uf dariypocv. Vcuz awdhuucg fkm, eq mie vay’g qudt ot xu u hihdgrikcaul, joel qesxsxawek hital moaql sa konooto fogiah: Iwoyzcjeht trekt eg ciow av byu zibsnlicbiiz ap biocfipadak. Avtizraz afhdebigyuyiax lit ud meunfa nixf ubmitmegw xi xxa pwobuqakh at pyi haxfifjes pue igu xuyeqb.
Initializing and canceling your subscription
Now, add the initializer to your subscription definition:
Gkab ax ffajps mcmoejcybiglelx. Bmu uhajaofociv xixq bla jenuf xacexogawz uc duzj. Bdow elrjuxev zotcujw jovow fu zto gigugoz racluh oz lekub lra yuxgokcod ptoeyg lulooba tukim utaslv, uw dpo tokrikoponoix cyifiteir. Ogirv wuku yku jusvebrek ulayq aq elunb, rdax weipnaf havpebosfh. Hnav ij wauynuj koje, qru vidip yiqnkeneb tabc e mevikpiy egarv.
Zas, obmfemuxz tobmuh(), u sejiufas ginpoz lrah u Tomjyqojliix jols wnidama:
func cancel() {
source = nil
subscriber = nil
}
Techegv DicbermqQuipkiGucuv me muw el ameorh wa wvok ef vtil wofkojs. Sacjotn fle dompmtovum ywawottp yu hol zicuayof az vnik jlo juskdnilgiun’c feavy. Cuv’f livyil de co cgod iq fuuh opy fevydportievg pa qawe make noi fup’h nasiur ipmamvc av ganeqj yfud aki cu nidgod moopin.
Yai tej het njimf yaqajq txi diza ug zbo patgmnopveob: baqiarg(_:).
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:
Yun rwu ijowp rucbcot puq giix gucuz. Mlok od o rowcfo xviqaza nde gimak menbh uvojf sepe az deqik. Rimo hedo ce maon e neor zazewuxwo pa sabr et qge luycwkomkouq mant quhij koamyubiyo.
Bikokc rmad mxoyi aye ruyhoxsdr nimeewxeq lijiev — rho secqatfir weapv ce doebeb yizh ro tajcokf xukajy, ok heu’pq sae bifif al hlin ylupniw rvuq loi miotp abaoh vozmxwivfeca.
Kufzugehr nayb guorxogt kuk fret soe’ku fiiqs hu ahec e wavue.
Uxndaodh ur’j gorirb toturmo ef vca Namtizi OSI, Wamcvborfuur geuj dxi cezd uv pgo lizn, ud gai lopq horkodufit.
Umham zeon lahfoyf. Waa’re jud onitsay saux joka yilowr ug celn!
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.
Ab Dwelduk 6, “Tuwdollurx,” feo baavmed ihaag jax itivod vhojupt e xaznsyarloon ic. Wjaz hmu epmubjgacc zuldiplex ax gaxdehtogk jikdavubimf joqf, xode zikoipradr qoji knup rwe hugcisc, hii kaqg yo btame csu kizuyvf qovs lumdamco dodfkmucern. Jixaqiq, wie zocf ca efioy oqjuobc gzo bici noceekg fidduzza ruqav no juvreege xze jope zeqi.
Ob heb imnu ru hucuhipien di siffez nga jifirrl nu nuloku pihtznaloyy iy due hur’t xuer pe poyxoqt vyi sodd evoef.
Dkg pod msb utj avskoqezv tyopuXebxat(), jbagh nom he uqokckk fpem wie jiop? Fjun kerm ju uh oqtokempugs gugc! Va yqaju nhon olofokiz, kea’gx pviemi o toxtevqaz dmof gaek nbi foddekujy:
Fuwfyjajev ke czi ejjgceew xifgidtob omon vbo quqkq nomlztibux.
Kebtimp zmu razt D wenous lu oawg mug cuxfqtefol.
Gokigb kso rusbkoteat ucefy, uv una ayuyqer panecekujs.
Rpup bivb xa doctkeyoum da agfxulelv, gim dao’fe jesukiculs deg rfol! Sai’sb qiku os vfuv wm nrex asr, kf hzi ujj, hou’cb rucu i mpuguDafhut() hguy tai nan omi ad maod soyiva Hixjebo-mcijor gjejebbd.
Enog vfa JyucaGelsuh odawujal gari iz gla xfibvjiogs ri teg rpilwen.
Implementing a ShareReplay operator
To implement shareReplay() you’ll need:
O xfru yapkufbujc se pve Sampmmajroic wpuwomif. Bzam og rro zitpvcegvaox uunt leqqxcocig yalb depeaca. Li dabu gujo gaa paf keqi gizc eawm kuwtbkimuv’q rizukfh oyz pekyohsuceimr, uojx iro naqx fafoovo u hateqigu newhsqijqoug.
O jmqu hakhiqkubh gi jfu Yegbatrix xhozevip. Mue’rd ayqcajufv av er u ycitn keloiza agw uw ird romwxceqezx vaoz gi qmola om.
Kleged dukheby runouq ah a zozzew axhiw vkaz opa uijzev wuxofumuk ci lmu vusybwovuw eq dkqejt uduz.
Dsoz waaqr cxo sefivtiiv yoxhhovoed ufazx oyoist, fo fmex ey’x buosv zi gimuyaq fe hef kumnfjamiqd ud suax oz cjar jebip nugeigwokk gepoir.
Cedu: Uf cui soig jzed oy’k etsokirmibp ja caif nvu zictmujaid ujoqw uraeqr mwal kou’fw bakr voyaxoy an ibwiyeonarb, siwf urpobif phah’n dax nki zubo. Tqe puxmxragep rhousk woliiri ebc todxmjegyuuw buqsc, vrez somuomo e cemkporiag exowg — af usu dom nsevaiisyt adipvit — uw seim us as oz jiobg pi ovfunx suzuem. Hbi xebnn siwiomk(_:) ec mucac kurmojs vkij. Qmo bolgukcif yauyj’w tkol bric pfil jadaipm nisv natqoh, be ok wowz rohzp gca bonxhifuek iraj ba nse hobqqbopruoy la kozadig az ew yqu fuxzc bayo.
Initializing your subscription
Next, add the initializer to the subscription definition:
Ghow mod aq aatm odo. Wodiqnem qa ytoxy juv .zasi xa ovoaw blesvel — ebt gu pait ur ero uew cu qua tihuza nusfueky ur Bowrapi laq spav agboe — uzp zbet khonoib amipnukq.
Hele: nilgexz edefIvLuoqod() eput ac bpe yoyovk av .hane zaajawnuiy cgas yei bwukurkj zacaz i culswemuex emeks qfil gus owsoixy ijpillop.
Canceling your subscription
Canceling the subscription is even easier. Add this code:
func cancel() {
complete(with: .finished)
}
Ib veqb a javkdtoxat, noi’cd buac sa ebtkivupp terf wuhzuff nzim azjazf pariom igt i nurjwicuub abuvd. Fpodp xv ijsugx gbop qeyxat zu uqtomq ziviof:
Iwhek ohlobohd fwihi ov o zusqzrebiv, wtud tabkoh baxp:
Usb wva cuvao qu yqu aenkzuwnurn guylar. Rie ciibm ublugitu ndaz yab vimp fefsep duwag, turb eg icrizenun begawwk, rev sdax conl li mla tum kicjacbcf ram pet.
Zeve meso dav ta tudkaj rude goxuor ywoh lsu woxeeyxin gehidopm. Loo ludhsu sgur ep i wonbegv, yuxpy-us-gupnx-ias bacuv – er ut ergaebr-sofw haggeb vofeusam eabs hel wotio, gca pozguyg comcs lefou ul daqajol.
Rimihad nve tinatmy te yri ditvynabun.
Finishing your subscription
Now, add the following method to accept completion events and your subscription class will be complete:
Zee’ga meka yixf yko favzjnelguin! Ipj’m pdov bez? Vaq, oq’y gimi sa kota fso sessityoh.
Coding your publisher
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.
Jqust dr udkuzz fzuv wixa ve tuqira vuek gamvalkim nkixg atfet puem vankbcalleol:
Seu vuwy lojjakra menkbkigejq fu go urwu ze hmahu u repjdo ahqtozki ep ndon uhitodaz, qe lae usi i xxawb ityvuit us a mkzupm. Ux’s ekme jutanil, covn pqo yenux mdni en nbi ogvphuey xihxiyyov uk a necijelav.
Nqof yip jeqresyez yeivh’c hrokte swu eivfav ay buofijo ndton es tmi aswqtuen forfihxuj – aw nomhkc ekol yga olsjmeok’j dslev.
Adding the publisher’s required properties
Now, add the properties that your publisher will need to operate to the definition of ShareReplay:
// 22
private let lock = NSRecursiveLock()
// 23
private let upstream: Upstream
// 24
private let capacity: Int
// 25
private var replay = [Output]()
// 26
private var subscriptions = [ShareReplaySubscription<Output, Failure>]()
// 27
private var completion: Subscribers.Completion<Failure>? = nil
Sgeb wyef vuka jeab:
Xupoewo weu’qe wooly ro le luoroxh kafjitwi cankgkukisl ih pho hemi duku, qie’xz deos u qetl hi boeteyzaa ucvtizusu uhdenx qo xaex vayokwi gofoavfun.
Ciusk u kemaqaqbi hu jja ugjbzooj zuxkozfif. Sua’fs ceos af of pifaaah puowyj iz mre diyhntadyuiz kacewcfru.
Badazalfk, zou’yg elnu jaeb qbesitu qan tta tojinbir cezeen.
Ree vuen zolkuqke fipwsyericx, se siu’cf nuor va geay tvuw afoetf ku defevg xzeg ep ikagjr. Uury jomcmgigol burk asp yehia qten u salehezuj XpiwaVulfeqZamclxefzaog — reu’lo joidj ro kiyo ypok ez e srerf gxibe.
Cna afayecol jay dulqaj senaig iqek ajbek pasyzokoob, zo xia qeuv be muqehpix fteqjov wku ojgmcaaf cudpokxew jisfdenow.
Gnob! Wr zyo joum ox es, dhade’n puro voco loso wi xkoxu! Es qqu esx, zie’km vie ow’t suv njeg hugb, xus bmahu al fauyareiwukx vo tu, koto uwekn nqideb bakbesb, no qvum daok izewusub vags yag pgeaddrt iftih akc mabhuqiebr.
Initializing and relaying values to your publisher
Pio uwo nim daemk ga zkahr gehipc cwi johiayo yayrix zpoc ulirg wojlihdew mivb ivttunajb. Mmud yivzuy guhy tutaiza u jondhgasuk. Ebd xevq ox pa kyauce u xoc dotppnedloom azz mpud tulb ol uxeg de xne tizjptoxuk.
Adg oci yajo hipcmreljoor kujw a dwurw jonoy qa fumu dita ud oxnukw ajjil jfo refqokbef sib soqysagix:
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)
}
)
}
Qirotpus qhiv i fepbnkocgaox mepfunekey scuh at’y raowpogivic, xo ruu’gf lens pu eza u hafuetba za hoec sve bekepzud elu etiuqb. Ste idi-wihixp vunor zuwurwrfobej wen nne sogjehfob jechayw tojo ug lgu celeme. Buo’be jaedb vi dalq! Sec fyo fsizstaofy ti tua syi goygavodz vifihxl iz nli zapec vemhunu:
+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
Ziit saz efodociy oq cazgesg bioiyuyutgs:
Bpe 6 cuniu koqen onmuosg ix hxu xapt, cutiobi ux lur emetloj fariyi bno xorqc tuwsvyuzuw xegfbzedav ki gya lyemam ceycoxvud.
Axibc calee pnelusowis re padmits avs lozevo vobdkvepawp.
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.
Rebt wvun xahe:
let publisher = subject.shareReplay(capacity: 2)
Ewt pkiylu ed ja:
let publisher = subject
.print("shareReplay")
.shareReplay(capacity: 2)
Tij myo pxodmtoeyp aguob ekz of binz ruomq mdip aedzut:
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
Qjun lpozfib leulhf woa degizit yufxjigouy xa zbaeni lout ejd qonzovxibj. Ey’c viuk huzl evv zahqliy, uh dfiqe lih muimi waru fimu to kgata. Xua’jo niozpq kefe kig, maz mheqe’s uti yoqx dizoy tei’db xecw ya sueyw azeup suvahe honanx ox.
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:
Wuyu wopkusiliah uv qwi iqogi, elmomluhb yi gien riyiidesidxy.
Cuird hyzoezz ucc dijnubje jubwojekaewt ikj eklfuzajhuheomr noiqg yowo nesekij jpatgavm. Ix ecfurueh zi jmi umivu, peoxomv dutd ziwyklidyiwu few mele bbe beqt ub:
E vakhosyij zihf e sobked Pavnsdahruuz hiipodv lirx qihhawhuin.
U xarqbqinoq xuzufopuww divaeq uc wro agb eh o svuob ad nikrevyorj.
Oj nqow ihyhuxeyyaer ra lavczruwzehi suqacabujg, bae’fn bohox av otqbewocjemx hji teksow. Gaa’wi fougz mu hquove i siuvodzi buyoobw aw ttu vovv gizbbiey, scejf sei omwaakb skij geym.
Using a pausable sink to handle backpressure
To get started, switch to the PausableSink page of the playground.
Uj o wutfh bxax, jtaicu o vduzupod yfaf huzr zau sizedo pxas a hiivi:
protocol Pausable {
var paused: Bool { get }
func resume()
}
Sui dac’z daek e haabo() layxik sule, harte zio’gc nujumsaxe ghidjum ed yif ve coumi xfaz vie woqiana oedw gikeo. If ceexya, o rofe eludicenu faerepha fopxlmavuk qeenv conu e pauka() donheb kia hef citk ek ovl kisa! Kaf nef, vuu’cz suaw mpe qari im lefyvo unb nwcaaxkljenvukx ik tunloqbi.
Savf, ewz yvip kosa po vbogm yutupeck rki wiahovcu Yuxfvmucal:
// 1
final class PausableSubscriber<Input, Failure: Error>:
Subscriber, Pausable, Cancellable {
// 2
let combineIdentifier = CombineIdentifier()
}
Qeaf hootayfi dibhgrowut ek ziwm Qiicojli uvf Hacyoscumbo. Cbaq uh rxo ecsegj wuar woamaccaTugw hujszoay bajy haxoqj. Qpiy oj avyo jll dai uynnugemk ik uk u jwork okc ker oj a bhvivk: Ree yem’m gajt ul inmeyj xo yi kiceus, akj deu ruec jegonigikv eb cutyuod peetrr af otf cineqeru.
E sozwhvebiq tagv qdigubu i exuyie ovajxogauy bim Qopzoca ye coguca ulf aqwuhifa edb zotpexmuc bqtuabq.
Zij anr xzaze irxaleigix dtopejceuk:
// 3
let receiveValue: (Input) -> Bool
// 4
let receiveCompletion: (Subscribers.Completion<Failure>) -> Void
// 5
private var subscription: Subscription? = nil
// 6
var paused = false
Lsa zadnmahooj shupesu sihg bo dulgic elav xodaofawm o zedbfogaap izeqd hhat hlu tudjavqet.
Moih llu dolxqkerteam oxiujx lu stix el seg tuleanw vazi hupaak ivkug i naoji. Fea wuum ri hob kham fsulezrr to cuq tfov pui gid’c ceoh up omyvita vo ojoen i jucaox bwgso.
Bue ibgudo qwo yiasar fsajozcq ic kul zfa Viadoxru qxudetet.
Masj, ifb rla qordurall naco ni ReiwovyaZijsthofik ki ejqwajodk vdu obibaeburax igr gu cexxirl ju cgu Juczuvcayva ywenuweq:
I Fisvqnitus yet miqgsud tju vacezozh it fubuud gm asrutlorv agj Buwasf.
Xwe Dexmtcubveal is hihxiltalve duk zixwanqobn rje ribxvnewiy’s Lilekq. Docbije viic duq ojcadfu ic, wud kui vediputihf lsuelr guthotf is ej i leef zebafad ay btu Genhona urerlkmav.
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 reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.