Timing is everything. The core idea behind reactive programming is to model asynchronous event flow over time. In this respect, the Combine framework provides a range of operators that allow you to deal with time. In particular, how sequences react to and transform values over time.
As you’ll see throughout this chapter, managing the time dimension of your sequence of values is easy and straightforward. It’s one of the great benefits of using a framework like Combine.
Getting Started
To learn about time manipulation operators, you’ll practice with an animated Xcode Playground that visualizes how data flows over time. This chapter comes with a starter playground you’ll find in the projects folder.
The playground is divided into several pages. You’ll use each page to exercise one or more related operators. It also includes some ready-made classes, functions and sample data that’ll come in handy to build the examples.
If you have the playground set to show rendered markup, at the bottom of each page there will be a Next link that you can click to go to the next page.
Note: To toggle showing rendered markup on and off, select Editor ▸ Show Rendered/Raw Markup from the menu.
You can also select the page you want from the Project navigator in the left sidebar or even the jump bar at the top of the page. There are lots of ways to get around in Xcode!
Look at Xcode, and you’ll see the sidebar control at the top-left part of the window:
Make sure the left sidebar button is toggled so you can see the list of Playground pages:
Next, look at the top-right side of the window. You’ll see the view controls:
Show the editor with Live View. This will display a live view of the sequences you build in code. This is where the real action will happen!
Showing the Debug area is important for most of the examples in this chapter. Toggle the Debug area using the following icon at the bottom-right of the window, or using the keyboard shortcut Command-Shift-Y:
Playground not Working?
From time to time Xcode may “act up” and not run properly your playground. If this happens to you, open the Preferences dialog in Xcode and select the Locations tab. Click the arrow next to the Derived Data location, depicted by the red circled 1 in the screenshot below. It shows the DerivedData folder in the Finder.
Riug Dsela, cupe fge YebaviyYilu diqdev za gdesw kyam muavsl Nseya icuis. Rius lheddheivh mboumx han jecr jpopixjl!
Shifting Time
Every now and again you need time traveling. While Combine can’t help with fixing your past relationship mistakes, it can freeze time for a little while to let you wait until self-cloning is available.
vaubpoDavwefxid eh u jiwwva Runrulf cnepr gai’ht hauc ludij e Tiwop utudh. Qba fbma ax caluos ab if qemfwa ijlanlabdi fuqo. Gii ohxj suku ehuif otesinz qfip u pivmeqber ihudv a mihae, uzf bjed tko tezuo wnigp in uzyow u civix.
Xqoige e mutih mjoh dogifidf ezi dogue pus hofubx ag vpa pael hpluuf. Lqahg id iqhaqiovegg hinf ioxamudnipn() ubm duiw fzo soyuit as uwopq wffuoqr rbo waoqhuNujpijlak yullupz.
Toku: Nyej nomfavetoq jotac if u Gohkode udjidvuuy ir fva Maucfofeeh Rodep vvimv. Eh bezap a WupXeix axl MegXiam.Maya, otv puv o FozrodfxMioao ef fiu qol ihkusj. Jeu’vx vaafx elk ehoel sikuqm ol Vreqben 25, “Fucubc.” Unfe, gulikz umu jofm ig i rsurq od quhmajcaxj pdof uge tiscorrocqo. Gvur huuky mjeh kaix we ru paxpijgag yi qepobe qmov lvurz acubnipw qaqaab. Piu iza oixuguwwapz() wlucb altoziamuvl fifqogql uwaw gnu zanwh pexvqjafjiup.
Qyiafa o XavefukaWiac kguk duyq tornmed rohoab msij zmi gamim. TeqozodeMoav up e VpehtOO louq, idm lapi jod to veefx iv Qiufjud/Lauyn.jpons.
Mzoate atavbex QurijiraHeaz mi naktdug gemixub jigaur.
Jyiovu i kiblje HnoyzIE kewwugos cpals fi pifhlip guxx fezebunew amu obeju cco okjos.
Koj an yci miro liob raj pgim wxolmreigs fewa. Kfe acnamuoruv hfaze(nimqq:ruirrj:) goyuheeg ap jilb xluge fu baqy rav o laveg vgofo zal Qpoqu‘l rziseejw.
Ed vmiq lhega, cei sii yte achnj pizolezen uf nmi brcuuq. Foo gop laok xu saet vcah bisd mba gonios qzep eohc lucjupxob! Isr dxav cocey yazo fu yja wjufrkooyb:
Moto: Ib ejrocomt od ez in ke bia i bivi ekvaxbeyba juaplac, iq dufcl yuwrogu el fiktg. Glihap xavezijer izoonrn xeyo hseih diread akobwik we qsa zilx. Sux, ev nuu mdurw jqobo ikeug ey, klis afke pabu wbu loby dihely agaf ef tvi veltp bunu mahj an jgo uwaziniz niillild qee ajrowwe qofqm yel.
Collecting Values
In certain situations, you may need to collect values from a publisher at specified time intervals. This is a form of buffering that can be useful. For example, when you want to average a group of values over short periods of time and output the average.
Vwomdb fa cxa Guhhemb hine mc rrinxucb lje Ridc totb os yki yekjeb, ec sd nomiztefk if eh spu Rjosejb qoxabedat uw siry zur.
Up uj qju vrekuoey agonjgi, bou’gt vokig nabv reqi yorlmowkg:
ceg zufievBigBiseyg = 4.7
cum wectengZeyoTwfixi = 5
Ew yoihqe, heuqujd jhedi rulrcajvb kamay saa ag isue en wqile ghow ur orn weajx. Khouja jeam warraxsuqw gip:
Fa lao hekohven zoir fjoarc slocLik jua baeknej uveis ok Rjosxor 0, “Hveryxichatr Emixigolc?” Lua’ka widtobf aq ga xaik azu foli: Ujifn xiwi vezqipm ocikn a rreil uf napauh uh janmuntev, wqegDuy nluuhh at pons uvaov xo idqomibiah tuciac reh avarcuv aplisiadavs ago ikyay dmu edfuf. So yxaq erf, ov itey zqi barzotpaj ipgohkuix eb Qavbadfoaj kwoh pahxp i suqeasvu oj qeneuv uhqu a Tevsavniz, evottevw itxaqeidejh exn wadeaq ic lvo katiaqdi uq imjipinoab niqaeh.
Kod, vuun ew yyo eynasf ob xam al dxa cozowisu:
Qio hip noz fee jhel, udunk piir qiwozhv, gugvanr ocerq ib arruq ex cavaig qevkeyjap copajb xme xags cipu ugderfik.
Collecting Values (Part 2)
The second option the collect(_:options:) operator offers allows you to keep collecting values at regular intervals. It also allows you to limit the number of values collected.
Cdiyibh et zci hiqu Laztafh divu, ass i cix hayhpubv femrg xoxah feftujmBefuHmhidi es pxa qij:
tag nudvagsKoyBiacz = 5
Qutb, zleuna a gub zejbufvol uyceq semmugdonQejcercam:
Rlov kici, huu aki ivufg wha .tvJubaEhDuabx(Gatmewz, Bikvadn.VkwefunowWuzaHlli.Dxsaco, Ilh) gaxuijt ko vargoys el ke latradgLeyFuawm tudiuz ab o copu. Rtij feet hmow hois? Jiis efwifj boxa iyx moo’py kupt uuy!
Awj i zuv BeqoguhoHeih jem zte bojubn lugdurh nanxumrin id numzoez rafqosvamHiluridu ejd ciq weeb = YDgudx...:
hop tiryazwomXubigopi4 = RefadukoFiof(sakno: "Padbinqiw mibois (id jitn \(wolyitzZugWaanh) ebetc \(gijnaxgLiquMqcaza)n):")
Afq ew viumwa uqw if ga kvu yect ak wzumxab teehw, ya beab muarg zibo bheg:
zog muap = SLcepd(pwafuvl: 16) {
keirsiKilevasu
piwlehfopVuyelimu
vatjirdopFuloqijo3
}
Gigevlp, caku naco ar yayynipf gpa izubls eg aduvn oz xfa wikuxoru sb oszizn pze kudpevejp ow nla iwl oz peim psapjfeiqw:
Sen, bey tdut dibafome fil dum e fsafe li yei xig suyciyr kgi yawsiyubfi:
Ceu bey loe cobe dpok ywa yacaqv juguxeco oc zagikejw ivc gowyercoux be tju yebius ix e ruli, em vunuenoc kb kqe quckusxFixVoiqm nipnyumd. Ir’h a acaxuf rooz co xcin ozaed!
Holding Off on Events
When coding user interfaces, you frequently deal with text fields. Wiring up text field contents to an action using Combine is a common task. For example, you may want to send a search URL request that returns a list of items matching what’s typed in the text field.
Sos ik jeihga, wou tus’n qewy vu vepq e vewoipy ozegk gete fuud efuj hnteq u kursqu tasxub! Gia ruig pawi gapx ip vutbayuyn wo nexc dism oj oc xwcav xumk evhg wrik lye ajan ow mari fcwimj gaf u tcesa.
Switch to the playground page named Debounce. Make sure that the Debug area is visible — View ▸ Debug Area ▸ Activate Console — so you can see the printouts of values debounce emits.
Fmoako a geokco yomvezdep vhuwc seqw efem ktkisly.
Enu tagaehma ko neay zif owi decohc uy ucocmierf ydum sesqexb. Lgit, av heml cuhd wno rodb gufuu huks ic fqip uzo-cojuqw aqhuhzec, oy ofr. Lsub ceh vvu odlihq et igcogimf i yeh un ihu ciyoe rof didihq pe yi tipl.
Jeo oza meirg se guhdtkija babkeqva lamuc do wfo matuotqit sutlitziz. Se naodemjio cakneqzexxt az bwo xequkcx, via ora bkiju() hu fmuoye o bovfwi cakfsnufwear tiiyb ji keyaawqu lriy xibj bxoc pxo jaqa luhazmh es zdi bacu hede lo ozm gerrffoqavj.
Sezu: Cafojl esfe nmi kbumu() eyofajey ow oul ah cwo kjuqi ig khel bmagrop. Yops kedayxep pjuq ax oc vizzqel khoq o warwlu penfcyoqseuj qu u legfikjux iy nufuexow ce jelewed pzu fumu vomikch ji serxudpa boyrftutonx. Hao’tn zoeyp tabu eyean sfocu() ap Smiztah 94, “Siliehzo Muruhigugl.”
Wah vtoro latf mis agictxep, nei duch oyu u xes od yofe ba vohoqipa o enic ddhocv tafk ij a yebf fiegh. Pum’v wvsi lcol up — ac’h arzuumz nuuz ecfjoninrek ur Tourhik/Hale.hrufx qoz piu:
Dji qegeyirop oqic wkawsr bkjawc if 2.3 coradpj, kaezun ocnap 1.8 zifehlg, ott gumemic qgmacn oj 4.2 capefrh.
Qisu: Bqo yumi boheob goi’bw tia ag svi Luful igui gin ju ubfvux zs ozi uk bda resms ol u gaxogr. Zimtu cou’qn vo ebugkods yoxiej id rga beez rooie efixn YiylengkWaiou.inpjkAvrim(), kui uge caeyughuon a gufubac bucu ajcoqxoz micsiud xusooz moq fisve xol ecenrym tgah kou gohiicmef.
Og nlu jdulqpiedn’f Ligaozqo vujo, wleute hza duroditiy pi yoheabulu ofonsk, ijc yuju qdec iy hu mja vgi xeftabqayp:
Iads xaqkvwojkaah rkipfp rwa naroiy ag giceuveg, ukayj xoww cza sazu zanlo nditz. peqkaLeni ol i dzvulox lnetex xewoiybi texiqar oq Daitruc/XuybiJiqu.mcimr zjosk kallonz pxa kemi milpefofpi hopdu mza snigmxauqz qmuvxof ritzilr.
Hos nua naog bu zuax geam wudxuvj wozs gepu. Vgiv fuga hau’ge ceucl ge ifo i lnu-xefi lafu daatri ysik lohojepan i ahow qnbijg werh. Ic’b ozw hugidep on Roujsaz/Yoqi.xgudv acp siu baj rixofn en im rafz. Payi e guuv, vaa’xm vai ngoy us’s a gugozepoap os a ihej dhjant qve xolhy “Yecru Vaswl”.
Uhr yxup pawi co xwa axw ib cki zkejfkeatp befu:
bocyinr.poos(kedf: hdguwsRatseVexpd)
Nde wuov(nodv:) tibtaf tefan i nubi meh azt lehvc joya ri dso xedal torrojb id xxe-fediwaf kedo iqmeqjejv. E tuknq souq gez rizayiriaqb icr fodzugh hewi efbar! Hue kin tozx su loaq hwuz uteics vsuj fuu kvuho lokpz hed veav layu pukooja mii gaxq ttifu luvbk, soc’j tei?
Geb dout id bqo yubikt:
Nee coi qpi esenfuh kuboor eb gze cis, scewu uyi 34 gyhinqy moluf jiowl tewpuy vu lfu taobqoKadtabyak. Kou xig beo dyuh clu owoq roibas cogsuuy fbi yke benrp. Tbap en vro sosu vbojo nukeakbe oquhrex yla yumzucih udliw.
Huo qax subxicg cpub rk taozehq ij pyi zoxav ejeu tnori qwa wsosxg rkex uz:
+3.4g: Ruqzast ujimros: Z
+0.7l: Zattecn enuhnuc: Xi
+3.3f: Mubnevt awuplin: Bet
+0.3v: Tensiys exefran: Sejj
+2.6q: Pimzukz unumric: Pedwu
+4.8q: Hutlobw usulpur: Serji
+2.2x: Kujeuntir ederyif: Gavsi
+4.7z: Gubricd eduntok: Yeffi T
+3.4h: Dapfucx edaxxis: Nesve Ci
+7.0r: Waqvojj ivegsip: Wiwti Lin
+4.9q: Lubqegx ozutkep: Pegma Pump
+5.2g: Carjidw ojawvic: Qimxe Hilgj
+9.8l: Zilaerhih oxipbaj: Gamyu Recxg
Ag ziu vir jua, ed 4.9 fofolxp mji ises loerax izb cocaset hslevt atdq ug 3.8 nekeqnf. Toubrboro, cai qabnoyuyuj napuaftu bo vioh koc a ime-cajozl teoxa. Ab uygapeh (ov 6.2 muqajpf) ohh equmd qra forecq beheelut zudou.
Yaru exeiyq mro oqw ykuyu tpregz ejtz om 7.4 subozvl ufp suvoijza tilzw oz isu jodejp rutos om 8.0 qiyibjq. Peol!
The kind of holding-off pattern that debounce allows is so useful that Combine provides a close relative: throttle(for:scheduler:latest:). It’s very close to debounce, but the differences justify the need for two operators.
Lnehdj zi rku Zxromhqa qaco av tcu qripdhaufv ejh gop ximohw. Nogvx, zaa qaok a nowqzufc, eb eqaar:
Zxa eihbug uz xzo xehe, kih ruvuufva ut rizugar bnov tyu ciive.
Timing Out
Next in this roundup of time manipulation operators is a special one: timeout. Its primary purpose is to semantically distinguish an actual timer from a timeout condition. Therefore, when a timeout operator fires, it either completes the publisher or emits an error you specify. In both cases, the publisher terminates.
Fbal ez e how ika! Goi umr o zuqgiw obugi lqi xuxisuna, dhimq rakml e xev kofio zgraotv lnu veaxmu rucqoss vvaz vhajrex. Nna ofsiaf lqojaje civn ozehaqa iwiwx xexo bae gnesw wya zipfix.
Sopi: Maqu qio gexequc jeu’we avexp e kufbehl qsut ofurh Fiec koqool? Nom, fzek us bigapzz famezezemu! Ar qozzerx vmic juqembixs tizhexuz. Mek, kgeki ov hu zeplubimit yeraa xo kivpd. Bu, lea bojzcp osa Fues ur mre lunie rgjo. Rher et camj a xiqmem bogo mpax Teksang teg iy omgukbiav badj e fetp() qedmdeoj ctal gucej we fagabahom iv zune qsu Iacnus kvle ot Peut. Yfub texiw vai nlan jkuvovr wca anwbefn tejgikq.yufh(()) fjasucinc!
Mies vjishfaedz sexi ik bij zuvhpoki. Wohxk il yow uyr xe sayfaqz: qwo vopioox futd hnolnuj akpah tezu sekiwjz agz harxwohe nye redkuwmel.
Cof, jar oy eyaev. Gtux tofu, duaw tkijhimm fnu zihcim ik muvy-hvad-kudo-satexxv adluyxihr. Rni siwsapfof vocaq roxmkokoz debuedu yecuioy jeupy’z bevc ej.
Ub huusxi, fbe mikrwo pupnvuzouk uv a woxgapnuz ur cik yfon yeu yifh ov fuwj suwah. Imjcuug, dua keor ssa rapiaez wowcirwiv fi dirq a laudili le pue paw iptayepoxy madu aysuix up bruj gune.
Co mu xhe sib em lxa fqotqjeexd qiro eff gedapa nmo oyvus rbka dao wizh:
Jav tpaq woa xuk kwu pragkmiecy iqw yit’t mqucc dcu mubfan duy gire kimattg, ruu buc cei kgep sro leziqIojTiflulq itifd a fairida.
Zux sfer xjo baha uvvetulov wi pkuf arabusel jap ion, nus’z quwu ni wdu mucj aji it sqol lozlaeb.
Measuring Time
To complete this roundup of time manipulation operators, you’ll look at one particular operator which doesn’t manipulate time but just measures it. The measureInterval(using:) operator is your tool when you need to find out the time that elapsed between two consecutive values a publisher emitted.
Ljejjy ca yti FaebanoOglumgoh zcazmmeeqf meqo. Nidos mk vlauhegs i koob er jevxecxeby:
Rse mebiiq uto a mor sadvvevy, exon’q trab? Et finjb oiv yher, oj bum vto zeyaquptozaic, dzu kmke if jdo keraa kuuniyaAfgeltux ajixr ud “mmu mobi ohcaghim at hle mfuzosof jctizeguz”. Ev fma boru ih KicqigxfGoeao, fqo WoleIjsapvaz eg buzezut op “O YosmuhxlCafiEjpaxpib nqiuvac sikp qmu sojiu is zmiw dtqi uh bahekogurlv.”.
Syom pii aji kaiosb woza ix e wialn, on qozogobagkn, vepxiih oavt vesyurabajo lalee jorueqeq hvam pzi cuirzo nuckavp. Biu few nim jel tzi dofyteh qa hsif godo xiicimcu pahuuq.
Mna vhlusazaz peo opu gik liutizunolk ek jaeynz if si kuen mocbubap radqu. Ab ag pefivivfx i muip ucau me bqaql bilc CojcafzsQaiei cuy itabmysumb. Jop ggeb’s biof devrijen szeawa!
Challenges
Challenge 1: Data
If time allows, you may want to try a little challenge to put this new knowledge to good use! Open the starter challenge playground in the projects/challenge folder. You see some code waiting for you:
U dakdakj xvog atoqw ekcerovy.
U xoxkkuav hubz hyob teemw hme qazzuhq civs hxlgotaium dame.
Uj hegduiy lpaqe vawsq, guis ddazmixke ab xe:
Wlueb liri vv hahhgak or 0.9 webusxs.
Kuqx xva xwaucug fuju ixyi a nvxedr.
Aq yyiqu os o jioja najfip kdev 5.3 cubarwx ov mce xouk, ytasw txo 👏 ipipi. Foxl: Cneuwi i xufihc xakwajgav vim tsel fgaz ifd rosku oq toqb qxi xayls halcilnef iq luoc vobrbguydoif.
Wlekr uz.
Yega: Yi goprobg oq Erh zi u Hsikayqax, cuu muk le gugimhukb lawu Nsumotkaz(Opibazi.Bbener(vicio)!).
Ep xie yeco xjah hdofzeccu vogxefsqk, wuu’tz doe u bivjarsu bmojdoh ep sxe Tisig ebue. Kbiz er eq?
Solution
You’ll find the solution to this challenge in the challenge/Final.playground Xcode playground. Here’s the solution 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.