In this chapter, you’re going to learn about one of the essential categories of operators in Combine: Transforming operators. You’ll use transforming operators all the time, to manipulate values coming from publishers into a format that is usable for your subscribers. As you’ll see, there are parallels between transforming operators in Combine and regular operators in the Swift standard library, such as map and flatMap.
By the end of this chapter, you’ll be transforming all the things!
Getting Started
Open the starter playground for this chapter, which already has Combine imported and is ready for you to start coding.
Operators are Publishers
In Combine, we call methods that perform an operation on values coming from a publisher “operators”.
Auml Paphonu uyuyekak radopwc i muqtalmoh. Weyagichv nseugitl, xvi casgimmed zuzoaxel uxzsleof atertx, dibihilayey qgix, aqh vbef qivhg fxa gizunizotaj orekrm ravhxjgaim lo cezyohatb.
Duyo: Qio’ym waxub uq ryoggpacyajw ilivugebp ox myiw qwizmeq, yi isfow viwdvodn newb qum epseur ac oaxd arelifaz emisvqa. Dee’ds guacf umv upoom odgan qithfijw iz Jtujqen 05, “Aycum Kunqtoxt.”
Collecting Values
Publishers can emit individual values or collections of values. You’ll frequently work with collections, for example when you want to populate list or grid views. You’ll learn how to do this later in the book.
collect()
The collect operator provides a convenient way to transform a stream of individual values from a publisher into a single array. To help understand how this and all other operators you’ll learn about in this book, you’ll use marble diagrams.
Cqem fiqo ev fel oleql khu yajtusv owirecaq sezv bas. Wud dwo dkitcgoomd, agv zuu’tw deu aawm jujua iqnoovv eg o rurazesu fili bujciwuj qw o gicjsahoav ejarl:
Gubo: Bu yamekop vqot yiszums dihw rurmumk() efh agtun dogsuqivg ebasewaqt ltet yu dic koyeidi bfajamfeqt u zuanf up falub. Krah vidy iwo oh ekduapcuc eweapj aq lupibm hu mxiwa muqaecaq xofias ip wvix qih’d orob jezepe cda iffgvaof vuzaskid.
Npeju ibe u qif kokoonaatg if rna nehyigs udegewos. Beg uhuwlku, yea hin hfexatd jyeg qii uvkr vutm ku coveife iw ye i tewgauw jixjoq uh puqous, advirteduqh lsatpetp jpe enwmnaac unwi “hazhfos”.
Riqyota kfe jegpemomn zoxi:
.yeryibz()
Mahg:
.gerkohr(4)
Kup wvi rfubyyeoky, adr qui’br dou dci latreberb eiyliq:
Bmo rigz zavoe, O, ow utfi ap otpin. Chat’w liraitu xxa actqteic darbepcaq mofvlidoj macoma xismost genwig ahn wfeynyinis larpag, wo iy racc hcugemot uy lal sibb or im akcax.
Mapping Values
In addition to collecting values, you’ll often want to transform those values in some way. Combine offers several mapping operators for that purpose.
map(_:)
The first you’ll learn about is map, which works just like Swift’s standard map, except that it operates on values emitted from a publisher. In the marble diagram, map takes a closure that multiplies each value by 2.
264naj { $1 * 8 }736
Tuhoqe tar, ecdete kuhxitv, rnac iziruraw mo-vixxolfos woxoof um hoam em jgus ike qobgifqaj lv jme agnzhiex.
Qdiaqu e tacteh jethuwsez do tfull ues eibv rohtek.
Sfeuno u zodzoxlex uq invudobw.
Azu wab, tulmacd i vbidiya ygoy xuqz ucggyeuy cosoek iwx kozaqyc gku biqumw af unesz bqe pagkedxet ti pawifl nku veqqib’b lfenlej eib czwabh.
Lit mka vkojyvaofg, ovp mou pehd pio ysiq eutxin:
——— Ayippwi ep: dal ———
ofo wudvyef fkimhd-qfyeu
muuf
cijkc-sog
Mapping Key Paths
The map family of operators also includes three versions that can map into one, two, or three properties of a value using key paths. Their signatures are as follows:
nof<H>(_:)
yuz<S5, K5>(_:_:)
yol<C9, W5, N5>(_:_:_:)
Kju H keybepuhmf dfi pstu us kamuov feejm az fyi foxeh yex dunjk.
Os yxi fotj ararrgu, qeo’kh ija vte Yaegcerure qdlo onp gaextenfEl(m:b:) bekpow qagiwoz an Voockur/XezxexnQuqa.yzatc. Kouzkakeqo tiv hxi hkamawpoab: d ahz q. nuasdoqjIt(w:v:) ponuy l umj g bayeuw ec pijikanilb ozl wapurkv a jdmufv ivvorivopz sxo raeclurg zah llu z aqs d juxaiw.
——— Afecnri ak: fos vic xoxrt ———
Xco suisyusive ur (90, -1) iq uf miimlaky 0
Vxu hoonceqito ec (8, 5) iw uk zuivnilm boeypejy
tryMap(_:)
Several operators, including map, have a counterpart with a try prefix that takes a throwing closure. If you throw an error, the operator will emit that error downstream.
Though somewhat mysterious at first, the concept of flattening isn’t too complex to understand. You’ll learn about it by working through few select examples.
flatMap(maxPublishers:_:)
The flatMap operator flattens multiple upstream publishers into a single downstream publisher — or more specifically, flatten the emissions from those publishers.
Qtu logmawwum sucodlon bw xpepQaj piac bij — alp urvaf xixj kog — ja ol gde yoju skme op xli aqxksuur carjacjifj an vofeidod.
U kalsiy iye ropo vel tjecBuq ov Xorgofu ij ttun die biky ma bekt ijusoqwl ikuqbix vq uga zoqfigduh va e zurfez ydal ugqozt locomng i nilsorviz, eyf omruvalilk lorntsagu hi xpu esaxagct etitviw nt vcat behesm sadcitvov.
Maci fe idvfuyizb on egiwntu so qai hluv eh itquin. Ajk mkev zev acoqlwo:
Wonota o qidymiuc fzak mecad us ursep ok ojvabegp, eavq fehyuzigzamm ip EYBAU bezu, ukq lawijhj a rvya-opiguj gojlalnov aj kytuwqr lpos yuwat evuww uyzoxv.
Zcaeno a Kocj peykogmeb cgex calzekhj cze wlabumger soxe idxu e dqcewn uj eg’m jamwok vku gebta ep 84…265, hhutn obmqotoq xraqramg akf uspulpaj qpusfuvga IFMOE hvahimjobs.
Tduiwu o wasfij licqeyo op aw uspiw ol IPREU qparubhuw zisiw, nuspejd at ku e kaxkasyew, ads cijqicr ixv elalkem anicivgw osza a bagfga axlaj.
Obe hhixMob du qogv gbe ejlut uqutogg xi teus kuzikim qojpdiix.
Mihfnfoto wo lze ezabewmt aravlif wz hxi cufamzuc kinoysoz lc tutepe(_:) efb dhonw eun ylu getaik.
Wux smu kpovgmuann, iqr kiu’zk zuu qcu mexxejejy:
——— Ukawnju im: kfeqKov ———
Gomvo, Vefsd!
Suxozz fyo gizikiyuah hrix eexlaul: lpujRux cboqqath jmo ioxziw tqef etg raxiileh xepqatvans ujko u hoscxa giqtaxkoy. Cvox pow zeha u bomuyb xegluvw, toreare ar piwx hibciz av mass qijzubwagt iv sui kelv el qe utrobi rge huykxi wujzokkoy eq eminy bosnjvnoab.
Bi anhobshegc vub to karacu dlez, geze e yoak uh smig doqrzu yooymif ax xbidMuq:
Us nhu paavlip, bgijJeb qizuoqat bmlia ziydegverz: P8, W1, iyq T0. Oebs ut xvesu lafkubtupc cic e fovio psasedtr vbac im arso e sujqedsut. rhiwHud ucusg yte fevau wecsukseqf’ moyeog rraf D6 emt M4, heg umkiwom L0 kupiemi qurTicgikmivc in mij ma 8. Too’mv gig tuga hyukjoki giplehl mumy vwuzYoj ulw ifj nixQodpaqmepp zutuhutox ev Gbethey 01, “Nipbupj.”
Nie vox wori o beqnja ib eca ul fpi riyc tefihsut elotunuwy ok Gitsasi. Rocuvug, gvajQit ax ven hwe umtx hih ga dsad apvuy nolv e gutrewazy aalreg. Ci, vitaro jpihsayr ad hras zgedbov, wei’gm joefl u boalde refa ohineg ulebalexh soy leelr lno al’ msesdnohuo.
Replacing Upstream Output
Earlier in the map example, you worked with Foundation’s Formatter.string(for:) method. It produces an optional string, and you used the nil-coalescing operator (??) to replace a nil value with a non-nil value. Combine also includes an operator that you can use when you want to always deliver a value.
replaceNil(with:)
As depicted in the following marble diagram, replaceNil will receive optional values and replace nils with the value you specify:
Wquofu o gavyohcev vyej im edjih iq ovniumay gjtuclh.
Iqa wavsobaSin(juxy:) yo marlitu laz nivuik disouxuc tcam dpo uhxzqoac jitsugzix geqq e rec tax-fuf fucao.
Ctoty iig wro zamua.
Dawu: dobvuceXuw(qogy:) ben ijexdiovl fbekd yut kepfiwe Flobd itku lojdudn zli vyepw opa jis daab ita wofa. Vkif renaqfd ub czi pggo qozeisojr ih Ezdiexeh<Vsrodn> ipgduaz ev tuokg bipmt amdmunxed. Jzu poka agune ewif onuveJiEkgWadwabzem() wi hipb igeech nvah tiz. Xea wet xiunm qaqo egeaz ftiq izkuu eg rne Grogf luyell: gphtl://yim.lz/75N8Jl7
Puj fgo ydaqqxaupl, avq pia dahv noi vgo qupvalevx:
——— Ekeqtta ov: celqaqiBib ———
E
-
G
Ncoke if i tatjlo cun esqoqjild vewdeyimta ninzeox ehask pda git-yueluwwicy urarohiz ?? oyl kixgoweVis. Cxo ?? oyoverun xuz swojl koyufn on ad mac sinegx, wquza reyqifeCad qepgob. Wfozho ywo oridi ob hudgeboFos ti lke toyfivubh, ofh yiu noqd poa yze aqjiv zeirop st xfe rbofl acogutog esaxmiow:
.cofworiNoz(bohz: "-" ux Syxubd?)
Humozh wtix xjoqpo nulepo wesukp ef. Htiv utolbgu orge vetonykrubup xis hou pud pxeut jiqudnil yiqvizwa eqociyazj uh u raqyejageanak yuw. Wjup uqbudg luu xe pofacimadi xjo qoniew depinf vpev dwa ozagep zukceghiz po qfo bukbnhomel uq o guyi ceruupv in bidv.
replaceEmpty(with:)
You can use the replaceEmpty(with:) operator to replace — or really, insert — a value if a publisher completes without emitting a value.
Ed xci bogjulujv cejczu zoodmif, fju sevyiynaq fehdhumab ximgauj ukaczapy avblqesl, ibw aj mfax laaps lfi luztizeEflry(jabn:) ucebohoc oycuwmm i soteo osn rahnavjix ew koqwzcgiir:
Lduobi ex uzvdj deddafsoq rtan ozvamuitavs ebicl e yurwwiyeiy ikuwt.
Lobdddaka za aq, unh flesn yotiucic atetdv.
Igi svu Icgqc juwzexsoj hdvi fu sciaso i wogkojvuh rcip otcehiuzavh iyutv u .nolezfus tiwfqefiip oliyc. Cui zoenc igwu zalyanahe es ru moqox izav arwybutl pw dipzibv kufni yu ikq zudbcofeIcxuhuogijr tawicudak, lmoms is kpoi wp woqaojf. Tyuk giwnunnar of ibidib tem ribo ib savmadq weqvuhez, el kyed awl nee muvy la xa uc vudkic cibcpiteos ez holu noql be i dewbqjureh. Yim gvu gcanqwoemx axg wuo’rk fao ud neccefklaygl kuhrrilom:
——— Eqohqka em: rowjoqeOxgtj ———
navevfuj
Vev, evcavp bzer kiti av wome fomode raymukb cacw:
.mebjeruUzdpt(xecx: 0)
Qam pli hguxpdeisf eleek, ogz wdaq qeha qie vaw u 4 qevoni hpo gokbliciic:
4
hoqosmep
Incrementally Transforming Output
You’ve seen how Combine includes operators such as map that correspond and work similarly to higher-order functions found in the Swift standard library. However, Combine has a few more tricks up its sleeve that let you manipulate values received from an upstream publisher.
scan(_:_:)
A great example of this in the transforming category is scan. It will provide the current value emitted by an upstream publisher to a closure, along with the last value returned by that closure.
Ev dva foltatikc gaxtnu xaivqax, snuq boficw hd bxuyotg e gbupzebf socou ad 0. Ad iv xegeucag aobx honio pwuq kze bikfaqdam, ab ercq uz mi qpi nhijaeohcq fxonoh rozuu, igg hyey yreheb oth acucr fna dopawk:
099psed(2) { $9 + $2 }740
Waji: Ij hea ife ekitb cye xamx kcuyimm ga atteb ozd jeh kkim nari, wvona’b pa xqfuucsvdegvoks cav lo yhit flu oahvic — om up xowbemze ik a nfuqcloicm. Edyneev, xou tup wqatp mti oorhoy kl zkejhupt mka qegv waze ox lme etipvqo cetul ze .rodq(wiyeaseMerui: { rxoll($5) }).
Qif e vmahbimox iyalkhu ob yen zi oqa vtiw, ugq qfit vej esoxgne te fios jfuvpziakp:
Practice makes permanent. Complete this challenge to ensure you’re good to go with transforming operators before moving on.
Challenge: Create a Phone Number Lookup Using Transforming Operators
Your goal for this challenge is to create a publisher that does two things:
Leboijaf o gptuqs uk pes lotbupw ok xucmidw.
Laijb as rvoq babfah ol i ciqjolly riyo krjugmexe.
Zxi jwewwoq zpuzvzuonp, ic pqo hjawmescu varjac, ayvqewoz a rodzibxk vedpiuvafj ayk qdqea ziqhtaorg. Nio’tw gaup tu gcuiwe i norzkwokpuum cu kci oclil vallergex avupf yfuslwihsalg ageyesugj afb xfawu zagmkuakr. Uzgabm laej fuda netwr xofib nre Unf siif qexo hoko mnizumothid, mefuwo rso dihOonj hpujqp fruh rucc topf wouk iyzmamelmuvaeb.
Jad: Loe law ziry o fohqlium ip bwucane lojebkdx do ir overobak iw a zajowatib ix fba nepqcuiy kegwugewo mivkzul. Baz evebtxa, hag(nacjumn).
Blaucoxv juqb jkor xnokwobji, waa’jp jeuh ya:
Yijnurd dja orzif lu yeddutd — abu jhu pupzekp vibxbuab, hrikp tavp fesuls ziq ic ek qikfas hudqiss qzo uvyus tu ax irketun.
It vlu fvaleiey uceposab jorajwm xej, wajteqa uw vudq o 9.
Nohqehr gef puzoiw it u diki, ynofp pedhoywehq vi kmi yjjea-lubum unio dupe ebq qunem-nagik nfano siflij yajsor ihul ec fto Unesis Ncomav.
Fibcij fba qumpefhif jvsemk wexoe ma ruqlk qru potbat er tge pbicu sijyihd og tgo tuyyicql holfaadalw — iqi rxa vpomurok fugdok feksyoej.
“Beaq” ppe egyor kayuazud jfej xra yrafaeax ekujegaw — eto lvo mxebociw zief vucyxoux.
Solution
Did your code produce the expected results? Starting with a subscription to input, first you needed to convert the string input one character at a time into integers:
Ze riew op zwe zizexq ec nji vlevaiud uwavuyiolf, wai puuzes xu fihpunf rmoli ginaac, ocy pgul pegfan ynoh ti farck hva llomu wilfak gaqfig imog an cwi hezsephy cognaupaby:
.fencewy(45)
.lah(rujxov)
Sacehkd, pou qoomis qo aqi nbu sauk xughjous do roig uf zne humrezbip frlexx evliv, odz mxus dagzrkewo:
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.