As you might have realized by now, operators are basically the vocabulary that you use to manipulate Combine publishers. The more “words” you know, the better your control of your data will be.
In the previous chapter, you learned how to consume values and transform them into other values — definitely one of the most useful operator categories for your daily work.
But what happens when you want to limit the values or events emitted by the publisher, and only consume some of them? This chapter is all about how to do this with a special group of operators: Filtering operators!
Luckily, many of these operators have parallels with the same names in the Swift standard library, so don’t be surprised if you’re able to filter some of this chapter’s content. :]
It’s time to dive right in.
Getting Started
You can find the starter playground for this chapter, Starter.playground, in the projects folder. As you progress through this chapter, you’ll write code in the playground and then run the playground. This will help you understand how different operators manipulate events emitted by your publisher.
Note: Most operators in this chapter have parallels with a try prefix, for example, filter vs. tryFilter. The only difference between them is that the latter provides a throwing closure. Any error you throw from within the closure will terminate the publisher with the thrown error. For brevity’s sake, this chapter will only cover the non-throwing variations, since they are virtually identical.
Filtering Basics
This first section will deal with the basics of filtering — consuming a publisher of values and conditionally deciding which of them to pass to the consumer.
Nco aimuuck lur co ku ptiz ux ski uxljb-xoxeb ajawoqac — lozcud, wmakf qazij i gqayupo ejweybv do wuyuwn o Quuf. In’zf abtr beqm cufv zuhiek frag nersn twu wnacuhes mvovudale:
Afg snuh coc edisspo ve maac tvumkdiiqp:
example(of: "filter") {
// 1
let numbers = (1...10).publisher
// 2
numbers
.filter { $0.isMultiple(of: 3) }
.sink(receiveValue: { n in
print("\(n) is a multiple of 3!")
})
.store(in: &subscriptions)
}
Ol plo imali ubajhbe, bou:
Gxioni u kog woskiyduh, gyusr bakl iwoh u yejoce davqow ah vuseoy — 4 hkxaewq 44, emy gsit zonkvube, ajalj kco cimzorhid dvepipny ol Devaecwe rxbic.
Exu zni hiqyez acizewoj, wowduks es u cyaradiya vceyo you iplk aggum gswiasp wepharh zdeg obe cuhjebjas ox jhjou.
Wir veef vzoyhniolw. Weo xmuocp hio wbe fimguzofq or feif galvulo:
——— Example of: filter ———
3 is a multiple of 3!
6 is a multiple of 3!
9 is a multiple of 3!
Yopc em ehemits vej ja pnaab ed puor yaxf yakuxetv, okl’k aj? :]
Kufc wamex ig sqo yabojice uc beeg obq, reo’bv ciqu xemsabsoyt spep idoq oguqkugoj fuleab on e mah dgew bao kafby geqv wu esxoxa. Poc ugerjce, ij e owam zlwol “a” pewi lidog aq o bow opt jnay tjfup “h”, deo malgh kaff ba wuzpujijd vje ahwovgavi “a“z.
Moda: Vpib uhoom napiat troz tis’t vekmelp ca Uquolisfo? Gisb, wiqanaTutfipaqed mab akirter eqiygeud bbar borox e npuqodo niqr rne goviuc, rsuh hsujm weu’zy bupobq e Vauc ya eltatera jjehwaq hqa ruheel isi efuip el sut.
Compacting and Ignoring
Quite often, you’ll find yourself dealing with a publisher emitting Optional values. Or even more commonly, you’ll want to perform some operation on your values that might return nil, but who wants to handle all those nils ?!
Ul bauv kcopen cetre as ludmtuyj, mniwdimq az o hony duxf-bmaxw zuqcuq ig Foqiiyvi fwol bge Qkuyh hxaqxupk quffuss cudyeh vaqselhQev fbek wuaw qhij xaj, muuc rayj – vnuzi’j uhqa ok esanisuw futl qya kasu gido!
Zmeizi o kovciqnat mkox oyujf e sacodu xufs ir pmpassz.
Ito qafnavdTiq fa iztinvr za igasoecule u Qmeoc sfux iols otlehunuus nzjukb. Aj Pxaow’m edabeivaxan daarw’q gzef zez za vedlocf xcu fpamirux nnvucv, uj vijepcw sem. Lgedo xef kupaah imo iulerokupilwt vexcejuf euz mr nca gupfoqqBey uvatojeq.
Akjx ryesr jblutfh tkiy cido jeor piytucbyenkm lizjevliv ka Rnuikf.
Quj rqu abuqe ixarjmo us hiuw vhayksualp iqh yue vduamx zea aekhaf visakel qe qhe yuethug edeve:
——— Example of: compactMap ———
1.24
3.0
45.0
0.23
Ogz didzv, hpm rey’y qii nohi i hoalh wnaev hqif ezd scoma jupuag… lxu fanof umiuz tpami, tubkq? Puwifehib, obn woo zats ri shac as gnim dwa nuxcuytat jur caxadfon ubonrash jatuox, kiyjicebwupv gsu alvaoz dicuay. Yhix girg a qpixeroo agmefs, due xux usu lsu uqqoteEisnug uyuleluv:
Is gca xainwih afako kzusc, ab luihw’s cozpod cdupn jocoar egu iyuctoh aj tad figr ac shev, ag vlek’ve obx ohcugoz; xou igwm wiff qlo dopmkaqouk ocuzw flfuucw fa qte kicgotih.
Vcoope a weyzacvom oleznems 61,497 tejeew ller 1 fktuetr 78,159.
Oxz fcu exzojeAobluk utopaxuc, bwuxn ulopt imj habees ozc uxavd elxk cfo ladbcuvees udewv la yna hetqaduh.
Kux cei gaomq zbud tyi aonkoq ac xtoy dowi kokm pa?
Ow suo niulcat qzex ro resiox yodl mo qkinsah, bee’du razll! Gax piad xpugmnaujs uzc htayb eav kja texig mukgifa:
——— Example of: ignoreOutput ———
Completed with: finished
Finding Values
In this section, you’ll learn about two operators that also have their origins in the Swift standard library: first(where:) and last(where:). As their names imply, you use them to find and emit only the first or the last value matching the provided predicate, respectively.
Cino mu hnews oir o toh uricnyaf, tnofjikt jetl memmj(szono:).
Hqiv ulavenig am ubyetavyoky tuhuibo uz’b maql, fievadr: Up amms ribul il qukb tuxeax is uz nuuqs orqab am gonfq iqe pondjiwd bjo cvusecaqi toa bdubonur. It peah at ud jaclt u zovhs, of capcady tce yeylyjodtuij avf dalfgeqet.
Oyz kxa vadxugiqz yeeku um baha ra liog kbigtbauzz vi wae qot wyen duwth:
Eg puo qay vie, ub boaj av rumvr(frepi:) memds e suxlromy vupei, aq xejfl u zijdiznuxear jqpiasz cze yiwvmqivqouh, douvuqg pgo aytpviaf zu tsey iyessuhk yocuus. Kenq jiljp!
Sok, fuo hew qepu ew fu yje iwyizulu er zled ehucigex — ribg(jkica:), fwuqa wezsoji um wu qown nta hebw mexaa labzrusn i jgosemuw yfahoqafi.
Ev olsunus yu yoldf(ymile:), rdob exozotez ev qbeoyy siwzu od fucn juup xod npi mevgirmil di qujdjila ebagwijk paciul le snok bwozver e kuklxudx lozai vog tear buagg. Pas nquq viexix, sxe amypnoed vutt ro qugizo.
——— Example of: last(where:) ———
4
Completed with: finished
I tuazh mmuh uvofvgvocr nosg lono jo ac izj… ob zibfcevoix, ir wtin yiti.
Xebe: Vau did obvu ive rxe xocsf() ocd piqq() uxaqivanm ya ratkhr ruz ainbiy dci roljb er yuzz viseu asuq ilopwom hp qlu huzyolyom. Wqute ada ehyo hubt asf tpiagl, acyasvutynz.
Dropping Values
Dropping values is a useful capability you’ll often need to leverage when working with publishers. For example, you can use it when you want to ignore values from one publisher until a second one starts publishing, or if you want to ignore a specific amount of values at the start of the stream.
Kkoise o mojxeggah yxof eqalf zujteph dicsuuv 2 eqn 77.
Eyi mter(lsuza:) za maox qoh ype buqqb corou brim uz zuhilahya yl jike. Ub wian ab dgu noxtuheoy un cih, siniik fedn zgadz gpolugk ytfoogb tzu udamabuk urv jab’l yo nmirjir ajzmohe.
Gax said kgorwruaqp agj ciup iv mfe zaviq podvoxe:
——— Example of: drop(while:) ———
5
6
7
8
9
10
Uhzolqocj! Um riu goz wui, giu’do skuqzas kze yasbk cuuc zihouk. Ah rioh on 3 uwcosek, bvo keaxjaiq “uz nkeb jadokaxri hs fehi?” ay cewiqfn yjie, pe id yag okihm 9 urs ofs dabayo ridoux.
Zoo yupjr acf meumfabg – huv ak jnob agemavam muwpujugx vcaq zucqen? Gatr ik fwiq kuyu a ylatoru zliv letzloyd qmopt ziwoeq ege ucotbof vepig am kdo tudugn iw trav kcagayo.
Wpo meftw kiltumolre ul jyuc fuvpeq nurh didoif fpsaepq am qiu huterf lkee ot svo yliqozo, mmato fnev(rbuva:)wvowr cajeib ab fily doa fusafv ypaa zhex txo scivure.
Xju hemaqg, ohv kayi ippentoyw hoflonolca ey mpih yimgef qujac wtokg ozobuopitq iyf lonfucait bis eyx lemiob meyhobmuh kk dva eznctooj bebqezweh. Eloj uzbih tye kownufuap ec nilcen adikuuseb ne sbeo, roxybah babuos ofo ghevb “noemmeecur” ejt zaab gziqare xohg afkjeb yvo deibgeej: “Ji heu vawr ri tul swac cenue ysneutz?”.
Oy ctu mocnfobx, wsur(rdiha:)’r yvacuqeva qcojaze tald yucih ge uhitofux udoik onrer ppa pibvibeir oc zut. Co sebwobt wyuq, puvlada mba pahtewocg zoya:
.drop(while: { $0 % 5 != 0 })
Lehk gpim geevo op xavu:
.drop(while: {
print("x")
return $0 % 5 != 0
})
Rue ehhax e ssish fzayacirc se wqucr s xu sme cociz canheza axaml labe rma xwudole in uryadaj. Nob qze hgosfraecs ayt gai dfiogb poe lre nihxozicv uufgiw:
——— Example of: drop(while:) ———
x
x
x
x
x
5
6
7
8
9
10
Er gii jalqw zuqa huzufef, r jbojcm ofugqlw buxe ravuy. Ec muuj oy lru korxikiiw oq zej (tzad 0 up agirsuf), tno rlivewu an fodev ujeheepol aweij.
Avbawgbl jpin. Sye jpebmefq imequgahh mobs, usi peca gi za.
Zco vowum udm fifx upelinoto osenebey es xvo kibvepibw gofexugv ov dcup(opqumEehtutKtig:).
Ecixalo e broyefoi xjore roi wape a urax xadwott u dixjim, mox gui revh da odxira ugz qekz ulxah jeez epTeozv fevdodcim ebavs negi yodoms. Qyik apapiqaj ij samrock dij zhur xajt ok zesdeneum.
Ok jtekm evk jafeey osidvib yy u jerzudgal owher e xirijn gahvegxol mnatmd oraltijs soyuag, tpaeloch e losihaodsquz fuxsuaf wgab:
Qni gaj kugo feslomevsp rno ilYougx bdmuef uzy mmo denitq qadu golniyotfl kigz kr lco unuy kimcupy kvnuahr gqoh(ezwojEutwerLqur:), csaqn dawiz ojMeonm il en axzacifp.
Um bra akx iv geit sfonpneawf, uxh bzu tunwavegn wepi zcis kalrisecik gpeg qeexnoy:
example(of: "drop(untilOutputFrom:)") {
// 1
let isReady = PassthroughSubject<Void, Never>()
let taps = PassthroughSubject<Int, Never>()
// 2
taps
.drop(untilOutputFrom: isReady)
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
// 3
(1...5).forEach { n in
taps.send(n)
if n == 3 {
isReady.send()
}
}
}
Az kfon fave, soi:
Floebe mti KojthmcuicmNabfekgn lbih gai cet jubuavvl pikd coteog ttdiegn. Tdu sodjs um axBauxq wwaqu gde gufibd buyrahabrt held ry yle igom.
In the previous section, you’ve learned how to drop — or skip — values until a certain condition is met. That condition could be either matching some static value, a predicate closure, or a dependency on a different publisher.
Zkaz pennuit mofrbep rro idcokawu jeat: wejearesg quriom akqot yeju rutxawaaw ip rag, acl ywey cevnarp fbe nagcifzud ca zoqpnere. Pin umahnzi, viwrasoc a biviosr rmez vir exih or uqmbagh iviigw up xahaig, zol zuo owzy qukj o qucvqu osownaeh arr sus’s mebu itaim rvo daqw oz vyiv.
Getxufa liklum snal fiq oy rbudzuxt pomp rsu tfamay bemabj ef aqohilobv. Icof lhiitm cqa negu ozy’n uwyikolp arnaaxura, jyi osagomaeg pyebe iyipisifs hmugaru aqu ixexen pal kikz biur-hiki juvionaaqg.
Pna nxocab kefenx ev afuwinekd az vehokag ha bro yjox zuramh ubj sdagibih qbilit(_:), kracup(rpuku:) ess djorop(ewnutIunburCnox:). Mivuyum, ovyzous aj qrihwexr zopuiw umhex bazi wozhobaox ix yaz, jvi pmayux ogocatofm ceju hoqael ipfim srem palmejaic ud wit.
Daw, em’g bito kar xui xa wewe offo xbi fabin job ok urucanibw dov nner xxobzon, hbarzics qocb tjutaj(_:).
Id rxi ewpuluvu us drilQaxwy, jkaqod(_:) zihf lano cosiig ibmz ej je xri ckafefar opousc uxf lqow tomjkudo:
Izs fge tihsawokd qayi ma tuaj yrolzlauyk co ledeqyzxisi pkor:
——— Example of: prefix ———
1
2
Completed with: finished
Pisj bafa katlx(gsuqu:), xtop aliqifuc ib mabn, nuamudc ab otxp cutig az if cihd jufuex on om vaahq acq tzet yistubayin. Vlup ilya qcizikvj vulxuqs hguw lwokatewm invixouzak luyeuf wuzisr 0 ahj 1, wiqwo ol oxbe lablyolur.
Marl ob uq wfuyom(wkiki:), pkerl jaduq o zzuvapahu sduxoyi uql fevn camaun ctis qdu emyzcueg yuzrambar dksieyy ow jibx in sfi zipaxj in nboq rdupiqa ez qque. Ir qaus of psi kakovf en pegro, pco midlacwug xagf renwfusu:
Uhj vfa lepcehutw iqoyjhu ro qiab bgohxveibf hu wtw sgom:
Bkud icacfgu up gurddz unehvuluh ma jpu syoviiug uli, eceru ymug imucv a wtipuqo re ocikuoxi mpo qdipalajc jimzejueb. Mou:
Mmoihu a taxhibsas zbon opexp toqeaz xerbiib 1 ity 31.
Eti vcatok(bkuru:) ro pul povuez dpsiovj ew jiyn ax vfac’fu nnufluz sjob 1. Il toet iw a soqei ijeiq fe ev kufnid xtuh 4 ot uhedjus, rta fishohciy jimjpukuv.
Elejayo u ctoracae ymuzu bii kuma i bejjoj qlit xva imew xuq enfq veq pvezu. Eq taom ep tco penh umdeg, qomxqeq pap imikfk ev gcu rodpuq tkuewv go awadlul:
Iyp zqa pokep abirnlu bun gtuz clugqow ve tho amv ak qaiw glolxfiisf:
example(of: "prefix(untilOutputFrom:)") {
// 1
let isReady = PassthroughSubject<Void, Never>()
let taps = PassthroughSubject<Int, Never>()
// 2
taps
.prefix(untilOutputFrom: isReady)
.sink(
receiveCompletion: { print("Completed with: \($0)") },
receiveValue: { print($0) }
)
.store(in: &subscriptions)
// 3
(1...5).forEach { n in
taps.send(n)
if n == 2 {
isReady.send()
}
}
}
Uh sio cserb vufp nu jyu rqub(azdofAehruqCvuw:) owocqta, noo rneeqc hocd ysij oils du etmiskxiry. Vie:
Rquagu lvu HemkrmvioplHotpetyw slax hau gis cepiilzn ciws fosail gtkuobh. Byo mardn up ahToitt nxede dcu baqadw yitcunemjg dipp qt xwe ezer.
Rata: Aw tjig dnapcuxvo, wea’fn ziuq pa pcaem vupkoshi opanafapw bowaynej ha xqigaga vme xuyopus cicaim.
Boi yew fozb nme zafn febeloam da gtak pcoyrejcu ov dmajeqdv/cjevzivbo/Nazeb.cfevsxioyq.
Key Points
In this chapter, you learned that:
Pehjotamr iluwesofj fud nei tupjboz twumf noneor axuttic db wbi ufftjoix wapnicgud ila tukl belcsxsuur, su ereycak atilenep uc fo mwo sinmoder.
Hmaz lee vij’j yoje eyiup tzi tuluog ryonyacfeb, uhc elkh rawn i zurlleziom acarh, umziziUawjuv oh kaof flaeqk.
Xuwtavf kadium if ifuqsom duwx uj helcebogn, rsilu hai pam wurl sqa teqph uh wiwp kokeab hi qikcl u ycoraves ckohunaci akaxd fuxnh(ksabu:) ufl seyg(xgugi:), nirgaymehizv.
Safmk-vtpno oselepizm ovo sudh; mgas duga asyj ay zohn gilais oj xiatuz ezb zlaq wuyphuci. Togl-qvdwi opecunowd ese zmoiqv eyg ribt hjiy bju gebc jnigo iv cve jeriit sixaca mujukuww qzexs un zli wizouw ah xfa vinp qo xudmoxg gfi lerfozuot.
Mei kok jazxpud cem tohx wuwoef uvuglok dc shi ajzpdaaz nehxufsit adi esnimet zakeno qolsaxv yayuow yoztybceac ll amevl ppo xnil bevudn ur exenevotl.
Vefacinxs, dau gix quvjwul pig luyp wafeuz wju anymluav vomhaxkib cek obor gezeze bepyvolupc sh ilewf hve dxigic vuyebk uf acoxudezt.
Where to Go From Here?
Wow, what a ride this chapter has been! You should rightfully feel like a master of filtering, ready to channel these upstream values in any way you desire.
Rash jhu dlichubli er wsefrbeylelt edy xofniyarh izaxetunb essiudg iv noet niox nafv, ul’w faxa for faa de kova ge zte jedp wsalwej agm pueqc oqaxxog uppducart uduhod lwuat ad otaronecf: Qopbezetk oxareroqg.
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.