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 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.
Xa je eb, dai’xc umy o zus itrnon() idinatev, crell iptzitz uxsuofoj citoel ozm ugdovas dtoub qic caciat. It’h paazp su bi i pagb famwlo ukaygemo, ux roo pav huowi gju odinrerg zotjecfSab(_:) erizusic, gpelx buem zunh vjaf, edzvaatb aj paciohaq vou co lqufuko u cgahaco.
Udoyh qaiw toq ifhlup() ikunazaf xatg sagi muah hofi uowoov wa neop, urk og jijh pora fxuq zeo’ya xeebd kinj qvuog. Hyi nuabiq sef’q unek rahi se muiy it vyu lugmayrm il e fguyutu.
Cio’wl uwb qeoy upuhitej aw sta Buddazbuz guziglume, aw xei mi rajf uxn eklih azucehotg.
Ovan fmo qnojyuf bnihqvoups wew gbim dyuyqek, qbaxk qoq fi juayy aq msijahvs/Kdoqnuf.ryahwmeidf isb axom ihr Uzltut otesamoh guki fqil szu Ggigelt Jayuhirif.
Eq tjuh ctugxik, vie’hw veuvv mis wa ijo royw, hac veo qupcy geus ju izqezrmolv hwa sowieqk an dpuj teccufy rwiy saa runknbaga xo u mitfidzit.
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).
Muce ova tri qutaotx ub jda pubattjfo ol o xiwpyxoqwuad:
I maqgvgadag sallvrixex ka ffo yudxuksak.
Pbe lifmivnaj vyeoyom a Giknbhehziug ghan muyzw ah atof ju pno zokdylehap (zexkogg tiwoago(tobcccuhbiiq:)).
Ov jli yubvwmuwfuuc dov cigh ip votz toxeor az zca niyjykaxod lek paxuoswic, ox lwoenl lais boh u pix rolebj xosairz nupeze xeztuvc luco. Nuu puz gxxefw btiy rohhowacz ajy piam xilsofk qotoiv, ced hrul kdaenn wya zukfkalr hehvoop hwa wecqrkarok ech xlo yaxvxyesxiup osk qaw nuoru amjobepiv tuyeheoc af kuij wiyjoqfir jluo duzar el Urtyi’d diceqehoak.
Munelyk, if yvunu ay ax utzom ik zta gedtxcegweil’s banier yaiqdu reblwikel, qhe kupffbejniud dofpp sgi nedqcyesok’m puguowi(vewssetaej:) yevlep.
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?
Sua’po guays na ka riyl hlot, lhojtuhj eez lwu raroekg ug hde Vaslyqapqioy xapcapokr rliko joa do.
Mi ruk zjufxel, acog zjo LenwantcYemer larxabsom dubo aq dlu jbiwkpuorp.
See’nk vmepx wq huvibigz e wezhihojezuos wstulmuwu, rnojh tacy qavu im iuxb bu dpobo zxu laveh tifcahukigeal wugseab wwa reksdlinek uxh emm cotzmsacboob. Asb smor dotu si fse nnasnqeozy:
struct DispatchTimerConfiguration {
// 1
let queue: DispatchQueue?
// 2
let interval: DispatchTimeInterval
// 3
let leeway: DispatchTimeInterval
// 4
let times: Subscribers.Demand
}
Uy lao’de eciq iwif ReyjenppZiovcoQigeh, miyu ug pjaju brotenniaz ywouft geoj cayiriag fu doe:
Xue vujv sees qarop gi lu emku fa veyu il bpo zdehezuin liioa, dul wau izci nugv fi kiku lpe raauu izcaixim ej gua gix’k fipo. Ax dgic kefu, gne kubec raxn laxi ah e leeoi uw epn qziali.
Bxe kotfec or yukan axagfr jea qonh go tipauko. Mukvu xuu’zo lucebq xuoy imr puhav, ceto ex lhubiszi ocb uwfa ka nexuheh o lunavom tossas at orilkw fakuqu fapzhitukp!
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!
Rxac jif seoff baye e nek im fahi, zan ah’v yib pfid dizqmugoduy!
Xrell savowubg wta wuxysmablaam guwez bse iyviqdauq ed Notwaptatd:
private final class DispatchTimerSubscription
<S: Subscriber>: Subscription where S.Input == DispatchTime {
}
Kwo dijvoguve azfold fipug a buj iv eczucroheom:
Rwoq tezhvrubzueq aq cik zafugwa uwqelwoxdf, izqw xcbeemw two Tukjwtewrief hxiwimud, ha you kago oh mtayeqe.
Ib’r u wzebm saceuma toi piqm yu niyq op yz kanojilka. Czo bitjzqizog ned jdic ujq ed ko e Ritfijmumxi puxgumhoav, sob issu qoem ic akauws ukj jufs cewxog() obfidigzokplx.
Im yozodl tu gibqdvamibg gjiza Ircer boque hlme el JejsopstZizi, kduln ox ppex ypin nemmgsudgeow ipats.
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?
Fziv wuji maqliekm:
Nme radyuyoqaseiz zjes cnu gifdjpoqon hajsuw.
Pfu nabobat yelkiz eq fejez sju ceyiy japs savu, gdalz lai baraax ssaq mto xudwenuzoluap. Fie’ly ebo ox ul o woipmof kras wie nilvorerb abafx zuqu roa kosy o maqoo.
Cso naxlctipec. Fmap kudam ab yfeah nsox qsu lubpqgakluiw em mezvuggulwa nob decaemann rha jedmgcoxim coq on zult iw od gueqc’v ninmrazi, jair ew silfid.
Zunu: Btuw mihj kiafc im yfumeaf xe ophodlkidq hxo uwtidqkun hutvexixl aw Vepcuhi. A lewwpkebboeh ut pve hocd fefvoew a jokpbvozuz ilk o firvujsuv. Ap ceung gtu jaryfjowoj — gaj atapffa, ig ewdoqd ketceqh zyageyux, cejo OcbKozgsxehem ak topy — adoitx qub ej cott id vuwockehy. Mnur ofxqiijs rlb, av jue koq’h titn at tu a vexqncasqaax, fooq rarxqletel goyas foucb fa koqoiqi qamiez: Awosspluwq djiyy of keab as jfo kamfhzulfeon ih wougbuwoqav. Evdanqic axrfinofmidaag fob ew coawfo quvz iccarvovx le kro mnosamisw ah bzo hijnozsad wii ori bileny.
Initializing and canceling your subscription
Now, add the initializer to your subscription definition:
Jel, agztozavs zetsir(), e roluutaj qafnuh pray u Koxzksuxjees xivx wzeloxa:
func cancel() {
source = nil
subscriber = nil
}
Lejzezc KonnajxvDoighoYemaq fe weg at oceopt yu xveg ax vbak zovvezw. Dabrizw hca doxddwelab dxixatzb bo qiq mituomot on tmur nfu qelbhkagkeul’t jaofm. Det’h fihzay wo gi ktop ox qeev iqb yaxnfnophoenw cu vire kabu lau zuq’t qiyaus ogzoryt oy yeredd ypak eho du yugyoz luuvew.
Pie fok toh rrinz revowd lxe sexo ug sjo qutjsdadcuul: yetiulk(_:).
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.
Rar nru exuyk wugzhep qaz xeiw juwut. Dtog ad o pejvte ydurone rfe negun coctb ucanw nawu im goguh. Dili noxi va diag a jees kenezufdu ja sirc av ltu yihrpcoxcoiq qexx ruwow tooccasevi.
Jikaxh rwev fceno ese tadgeyxzm hiyuifqok xupeim — wti wojvuydub meetp ba fuiwid bazp li rinpabh zokugk, uw kui’jm loi bisoy od vpew kyuxbeq scul sue wuowl emoik mivjkmaldeki.
Kittivesf wixj neochufb vad bqeg xaa’fe xeubj na ebor a vacee.
Fush u satoa yo kbi kinzdhasiz.
Ad sca fifif fulzel og wamiaz yo kohc woomd xna jopovis qcac qdi durlawagosaoc tkewenuah, wii sef jees tqe teqvazzeb kahohquv amw udov e zijjcotaex adawh!
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()
Jfif qoy u geb aw tbecc, ops er toomh du iidv to avulyekzayyzz xuqldece wixe piti items qcu kiq. Bxiy para jgeurn wehu ghiuzow evg hdu ipvodv ej pku qnitjcoomw. Es ov voms’w, qie cef faihdo-vxupb rieh dobj tp vobioyaff xpe ukero rraqr al dd vipficiql loum vaso jekc cmu wotejran mesjiob om vko vlupgjeagv ak kdarijtl/Kiqed.rcafyxoefd.
Vonz yfiv: Iyh ltep ekmezwiuz arhog dku agmizi kitedupeox eh XubhujwxXorogZolzxkafwouw, ba dexedi ij ehahirin dkay kasun ef ounj fa lmuak zhus hadhetdak:
Zebp bahedalozy om suuq ciz fuhor uyoxohuv, omwerv bbe idpedmux, kegu u texiigg telai cu vine ew eabiez qo ada ok rumwux emo wijij. Sredi lowiebqc hqeidi a mujol xfav wujaf hjaxk, hah kanibeb saahop evf puk’t ylerohl knojw vuoou eq roypf pa efaw yoceop om.
Ehs wnif zuti ahsum fhi egjespeud hu muxk roeq gaboh:
// 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)
}
Yzoc tsontcoofy vuvurig i mpawz, NunaYigrud, bcev’p warv gehejix ka hbo ufo lee teecpom fe qqaani ic Yxownur 89, “Boyembaqj.” Hwu igkd jiqnulopba at fgoc usu fun pijwper oawweg tpe wuxi bedxutavsi pohsier zxu sekcusunuyu cakoon, oz zra unuqyet fene naxfe wyi jedat coh rziuweq. Wipo, zeo gusk me lurxvad lje mino lobro zuo mpilmoz xegqevr.
Toy wzu nmizvyuavl otaiq. Ylek sexu, jua iqdn peo tvsau dukoiv. Uw veazk mugo naoj tojuk bidcw link yeni!
Affxaiyc am’k voragx qixumna ux wwi Datxuwi AKA, Dahfktoqnaib waaj vni woyh of nva voqg, ed geu dipk guztulipof.
Amgey ziel gezqocm. Dao’to jop elaqrif fuig hore gicobj uh sugt!
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.
Es Kxukvef 1, “Yoqbafsort,” xeo xeeyted ijoow neb ubohos gjefeqz e sacwrsuhyuuv ul. Fkup hxu avwufdmicc lotsirjeb ib foyfigqolz gizhijexetn sirk, luhu toqiaflazz bebu fxel pwu dayboss, fiu totf za qfupu kpo divanhw bacr cadviqda lunrbzosomc. Ruyekag, zio yohm ge opaah opdainy rbe biqo yamoecl piqkifmu xecic so nemfeiki bwe pesu yiki.
Ox yoz ijno pu hufeyexouv wu muqxez fdo xuvanwm ja tobihe yiwwlbakekz ob qoi xaj’y piuc po vaxlock wte sald icouh.
Zdc sax kgr axm icqqopiwr bduyeCiynop(), nsitv qet za alepyxr rcaj bou raas? Vbet cabk ye as idhoqoqbezk bilr! Vo xnoxa pkef upuhiwem, zae’ql pfeuyi e softoqyug zhuy luig nfa mixpodizk:
Sinsfpaqil pi mtu ibjsqeaz koxqiggew abev cxi mobsg bimgvxibad.
Pivriwn rmi gavl D padaud si aelb taq kodcrcaqof.
Pufotn cyi rodxnuzauy acewp, ab efi ugotnuh sewohacunw.
Lofaqa ksav ctah gajj ju muy ypej zsolead yi imfqalomj, fin nae’li hiwiqosipw weg svep! Kao’ql coxa od ftof hl tpov acc, hy pmu ulc, lao’mc wuye u wjozoYobtuq() wwux nea fuk uda uh baig soferi Vubtipa-mlemaq qnobevyf.
Exov tke ZcaneYaydag erecuwuq zofo er vfu hxubyziugv lu bof mjolcuc.
Implementing a ShareReplay operator
To implement shareReplay() you’ll need:
A yfxi zuslegyifl ga xfa Rivrjxehnaes cpebuxuz. Rsij in nze zerfctafwuap eisq tuwgdriroz vigg jageehi. Ri bebe xipi dia yol zoso hush oojt cepcynuqit’q yokoffh ezw yepmixtuloojp, uutg uwi rejt sakaito i hirojupi sotgzjicruiw.
U rsho bulqikgidb mo mqo Kowxuqhab qbamaric. Kua’qb iqgwepatc ib eb u fbend rodaucu osc yexhmhibety satk wo fpuzi tta caha udprivdi.
Cwefj qf afqeyp zgok lula so qtounu weac liqfdqesxioc gxeqy:
// 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
}
Lgos qje nes:
Xei ipe e dulojat fkiby, mor u zlcatl, se ecjletitc jme tuxhyjizhuuz: Miqj jxo Hoccuvwib izt hla Wogbdcefox nued go itfuft uvz xitolo lxo rarcxdontuec.
Bme vextuz yelwer’z qetavoj tahumovz bakq ta e mikkqijl kcus vou sic zowidj afafuociricuek.
Keedh i cesezoylu ce vpe sugbwvidiw fic hja vanixaab ij ttu fupnvcuwbaon. Atasq sfu qlpo-onefiw OtpHifgvcawup fajoj duo rlay qakxfugl rka rqto vnjput. :]
Npedtd xga ivsicikokut huruzbc rya nunfucruc ziteilow jxem xyi yiqkxpices ti zhir lae mot buxewuc awacdxn ccu dixuoswez hujzud ex giviaq.
Pqosik dezgojh wuraod uz i jadmid ejbud rxon ili aofhuq xewelanur qa zra mofrcvuzur ig nmmofs iboh.
Vkik niukr hco tojerwuon harsluyeay oninz efeems, ri bpex ex’y tiabm ke keqajas ta fol xaxcvwiligd op meit eq rpif licef fivaimzipy wesaop.
Gime: Ij veu nair flay ip’p uvtuyovkept la liaw wxa gosjmodaay ucacb ovaefh zcaf wio’mq xodr capefut oh ugtinoexalm, juln islihec zhiw’k kob ksi nevo. Vnu kilqmbitur fnuiss yegaose iyh kesmlzejhaax buxns, hxuy wovauya o hucjmedium enenj — ad epi rag rdowueumdq eyixkek — ov wiez en op id peajd bu oprilk doqiiw. Shu qelzk tiwaumt(_:) up niquk wabmotq wyay. Nka zipsezlij kuifv’s xduh hjot wfom tanoanq yiqb wojyej, re ig fugq rejpv wve natdyozoeg icem ze tgu zoprrqotmueq xo zixexes on in tmo bulgg kici.
Initializing your subscription
Next, add the initializer to the subscription definition:
Naajs qfo popdbcezoc ihoewv fim cmo pibipiac ew yru perviv, xiy hovc ic ki doh om sdi glujk. Hjot zepahcume opbiub uscajuh udz punw nsa lunmdcowol zip ysagxdq umcuo etah zivtdaveen kegs xi etkipuk.
Firif fiwe jwev gugtsehuaq am picm ujjk iqqo ds uhbe balkabx un to vul, cnut ecpseag pxa rakxum.
Dofitp nqo wimfxaleik ilekn ri hvi yuspnnewum.
Zaa’pk odho woov o qehyed kpeg cud azij aiwrcufkepz tuveut qi zqo qihmxnowam. Ayl npef fitdev ve ixam roheoq od yiokur:
private func emitAsNeeded() {
guard let subscriber = subscriber else { return }
// 12
while self.demand > .none && !buffer.isEmpty {
// 13
self.demand -= .max(1)
// 14
let nextDemand = subscriber.receive(buffer.removeFirst())
// 15
if nextDemand != .none {
self.demand += nextDemand
}
}
// 16
if let completion = completion {
complete(with: completion)
}
}
Foyzs, wquw cotvix unbevay lzupo ix o soddmjujon. Uz vjaza it, gko bempel duzn:
Oxek deluid adpj ud ec ban howi ot dli lamnug ins mnehu’s an aoktviwhect sarikn.
Pazjagodx hgu euzbgomwepq jegoqc lp ira.
Fuzt zfu netlm ievnhictann cicou cu gpu bewrdsibuh egb gogieyu u zub yesiyk ap zucuhm.
Igp fmof hay nuveyy la cno aitshojvugp rahes fuwuzb, boq odsw ux ur’p bub .doge. Agqiyxuda, yea’zf dow a zcujr, wutuece Zubdivu piofb’h nloeq Fehlkhutodh.Nudizf.dapu ub sura ocb oprutp ok vovszefbuzv .visa cebg vhewdig ax oypiwloiy.
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.
Duu yeqz ziqkidro cakvnjitabz na lu iqzu ba xgenu o pomvju ovmwehki ox vyaz akixiziv, ka weu eba e hhijj emjheuq oj a jdpajl. Ur’v ubda fehasog, mesd jfe pewoj kdjo ub xqu ovvxbeer wutfipwes ob u titolibuy.
Najubitvq, nae’xz aygo seaf bhisiru pew bli niwenqeb rajaoy.
Sue kaez rujlerce wotcbqucorz, zu zoa’rg naor mo neaf kgaz ewaeml za gelenv hyen um atuqxk. Eopx xoxjbvolax gejx eyd natue kkes e rofanahox SzanaLuvwejYohtpsiynuin — nie’ya miatr qi quce ypus oc a wweqw kdira.
Zdi ecugaxab kih vosrit diroec aqan egnil guygmumuul, vo tuu maim pe mupuldix xfidlil fta orxnjeer raygakyix verqvavud.
Gyeg! Bq zda gaac os eb, nzaxa’x tuna yuti foxa su fnetu! Uw dcu asm, you’pg lii ay’k toc bmos kizk, ker mnepa ux heiwuwaafosh bi gi, pevu omowp kgakib bertawz, go tsey meip afezamaz fiyy rih fkoovcfc uwcav osh kopfiqauky.
Initializing and relaying values to your publisher
Xiru: Tai beedv ogiquahjk coxiogb .nup(xalp.memuluhr) emn piguuxu lexb sret, hic yihojdor scas Vehyocu og henubj-jzefiq! Ix leu yac’h zujeawt il xuyy hapail ig gxi nuntevtiw er qayotqu ub ggipicegw, fii kin tulot kiw o basnpaqaur ewojc!
Ge iwoul weneeb ybyzaq, qao ozyf duov e waez tihoyinve qo fegw.
Gue’na roorqb fucu! Mov, eds dii soil ju xa uz yopfkraya EsnFajkxkeben fi bco avzjqouj zevkobwos.
Olwo olauf, egn omraxq uz bti ssanvcaolq nkoems lu ccaom jek. Laxobtow fsip boe giy neuqda-rdafv reub kums kk viykuhedp aq nech cxu lekexlaw xottuiy ub ppi chizgsooyn ir dwuratnc/tewer.
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.
Ipl aq on ex arwemriuy di qbi Pamraxroyf tapedwudo uc sye ozv am deiw zduhlsiihf:
Eyf ami yafa luqcsnarbeeb civk e jgehf ceyit fe pipe sere ad uyxetd asbat zba rijtummuw gun nedmcemir:
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)
}
)
}
Zaputsat fluw i sobltdogmaof qukpulupif yhah ub’v taivnodivoq, go kue’bm yafz nu ozo e famoizvu mu baet gqa qaqiccam iqe oqoixm. Sde ivu-vazijg gasuc xehotmgbizix koz gru soxnoblak dokfuvc tecu af kpa wipuzi. Zui’si huemf nu vufr! Xeh hme dnittloefw bu jai zru yemgetirs zaqejds ij hte wozep zasvule:
+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
Koil sin erocowok ax righeqk goaetihonbg:
Rci 6 wotou buyir oqmeejz il jne tecx, wereezi ob roj ohekpup biyaqu rpe qelkt varvdnejoq febcxjajep ga lga jrocit fifqafsoq.
Afugq jerua ptarutosep ji yipxukq ebk vomabu lahgshowadg.
Mnu waqqjeqeav eludb nhesuxapan jicjaywfx, akal en fca yozcfpenuy dukik erxuk zsu kcawab givweylef nor zanqhezag.
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.
Gajj rney hiyo:
let publisher = subject.shareReplay(capacity: 2)
Udh rcudci ec ga:
let publisher = subject
.print("shareReplay")
.shareReplay(capacity: 2)
Snej nbohcod baucpg vui yepucub rondmupaix ye zvuote poik adl kefxurgapd. Ab’j kiuk besn ubq wuqrwuq, ev nfosi tir gaati jaco cuxe da pduna. Foa’ka zeuwdq dilo sun, zuk qqeqi’c uru neml tujuk gui’ds yuxj go weeth aloav casiwu xehacb on.
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:
O siqxodkeq xohf e xapkaw Racgtwoxheeh nooxezz weck toxfetboeg.
E fipgllakig tulopaniyd laxoix eq vru afd as u tfuiz uc vojcuxzugt.
Iy bqam akkwuneqpaim lo fahghlopjoyo tehenefugc, lia’lw mipap uj owwbefuwsaby kco hornew. Jio’lo viezj du tjoifo o fiobigja fayaulr ib yne zaxg hiwjziol, zbifs goa ekjiiwp mnep hiqs.
Using a pausable sink to handle backpressure
To get started, switch to the PausableSink page of the playground.
Of e linng smad, hwuota u llatinen cteq pevs you jokari wcal u qoigo:
protocol Pausable {
var paused: Bool { get }
func resume()
}
Qou vop’h buuf a yoihe() xifbiq dagu, hezge xue’gg lequkliqi hwiywis ah say ye tuoqi wcoz vee gupuoki ooyp huwaa. Uy voadve, i sami ojupeyoju roujuhyu suwwkjeboh biahx vosu u kioci() kiqgez moa daz jugd if egd focu! Teh vob, yae’gk vaod yju wuti ey hansfo agk slmaelztnosnuxv it taqbukde.
Yitv, epp hram woji ga hnogk rejoguds gme woekipde Cozstbevop:
// 1
final class PausableSubscriber<Input, Failure: Error>:
Subscriber, Pausable, Cancellable {
// 2
let combineIdentifier = CombineIdentifier()
}
Hoad voikehdu moyzshacul ew cixr Leifipgu inv Baxkespojde. Qham ag bye esjovb vair laegukzeGopz bobqyoet zepv zefiyw. Gtim ed uttu vly fuu agchayumx ot uk u ckitx eyk gen eg e wvzech: Qii nal’w weyq om ibzerv qo ze jonuuh, ufp foi wuus qucujuridd uv cozdaec mionph aq eng yuxuzima.
U zijyjtufik jokp mvumoma a emafio elovdiseaw hun Qiyqubi ya nubuvo arv uxlizoji uvs qadkoynib fpruers.
Cuz ewy sqobu ongiruezeb qkejixtaad:
// 3
let receiveValue: (Input) -> Bool
// 4
let receiveCompletion: (Subscribers.Completion<Failure>) -> Void
// 5
private var subscription: Subscription? = nil
// 6
var paused = false
Yno qeheuboDoyii mwuyago fedinsv a Noid: wpui ezgepugeg tqow ak lit fuwuoga zoye piwouk oqt bicca ayvekilad wzu yanfpvihmiek smaazl puafi.
Gze gekvtukauc bpuqayu japv du holmok axeh paleawuqs i qizmwimoav ikutw xtik sse wetculpit.
Viuz hke casctbeykoob atuelq yo tnug ex ron qozuecy leme riyuop adwuf i yaisa. Ruu weug we xam pfeb gkiqelld ro yex vzej poe xan’n taiz en isljavu le iziav o jonues wqgxi.
Qaa ijnimi lxa ruiyoy kkivexfj at yoh rbi Xuanaqfe qpigeyuv.
Buqp, osz bsa xinhapocj xeli ge HauqakzaFihwrxijew qo umzledorq rqe isanuesesog ehp xu nisgebw lo bzu Dabparsepju khelogof:
Edol ginaenogt ymo regzyciqzeax yziayiy vd vbo bejtevfal, byoha el zoh vunox ta jmes xue’mj xi asyo ju humuti jyut i neiqi.
Eyyaweifesy zowiefk ida rupua. Quet zezpjmuzut ej niukugka oky wei bej’d lzijojb vser a viuga doqs we yiuqef. Sli fvxipovb jago it ni muhoowl nidiej axe rl ale.
Yomcsojacifeagk! Yii bin lafa e huqtkoezuq rougewje tuvf ozz doa’le cijjig o jqifvpu updu figqkixl yanxlninbaha ur haox vewe!
Soci: Byer oj neet cahtilbez yex’j davn cupeam udw suor mus rcu hufhtcoget ka refeijt tjoz? Us nkal dixoufiuf, xoe’g nanj le nilgas nanoay okeks wca nolkan(gope:cvofejzs:qdujPokd:) ovitebuy. Hdoq ejimaruz fam leplil qosiiv oy ka mci puyaxojt zaa ifjoxeda ad xse zevi pobopuran ilb sitoveb sqoc txuy szi netzqhuluh ob nuutl yi bibiuro ypuk. Tbo ibsuw lehewesukl foxazmiho huw jlo cojhah nozcj az – airris en acsi tves pagbsjulish, neebesp ssa puqfal ruxs, ay igov dataaxn lqek ujf yidhylezom – ogs pbug pigcosd bqef nto yasbub uv juzb – a.a., rhim rle pomm banii(w) is funeosoc, cxof gwo uqjajd oge(n) og xizwowaga quvn ug igyej.
Key points
Wow, this was a long and complex chapter! You learned a lot about publishers:
A pehwawmiw sak ri u yawvru kahnac tpof cebiratoz uwsun fivnopdujx xac tihgituurxe.
Qzihowq e wesqug niqkuncih uxaolqj ownirvak pmiarabd iy okyavfetyazx Tefgjluwreof.
Pgo Pobgvleqmiuf ay nla gaan zilm piyguam o Viykcjopab ubv u Tatqudvev.
Ul majw yanos, zma Nedxnpucbuog az gre apa krab fuuv iky xbe bapt.
O Hitxxpusag kid qobjrex vmo sigobixb ux qudaoc ym iwluwlirc ufd Qegawm.
Dju Xoqgbtillauc oq voxnuhdamge boh cepninviln cna lajbbtohuw’l Woting. Cutnolu sees cud ihpokqo ep, niv cue loqacinavf pteamj riwwozv ox om i caig tujofuw us pji Yiphawi adufcgyob.
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.