Timing is everything. The core idea behind reactive programming is to model asynchronous data flow over time. In this respect, RxSwift provides a range of operators that allow you to deal with time and the way sequences react and transform events over time. As you’ll see throughout this chapter, managing the time dimension of your sequences is easy and straightforward.
To learn about time-based operators, you’ll practice with an animated playground that demonstrates visually how data flows over time. This chapter comes with an empty RxSwiftPlayground, divided in several pages. You’ll use each page to exercise one or more related operators. The playground also includes a number of ready-made classes that’ll come in handy to build the examples.
Getting started
For this chapter, you will be using an Xcode Playground that‘s been set up with the basic building blocks you need to go through the chapter tasks.
To get started, open the macOS Terminal application (found in your Mac’s Applications/Utilities folder), navigate to the current chapter’s starter project folder, then run the bootstrap script like so:
$ ./bootstrap.sh
You can keep the Debug Area visible, but what is most important is that you show the Live View pane. This will display a live view of the sequences you build in code. This is where the real action will happen!
To display the Live View, click the second-to-last button at top-right of the Xcode window’s editor (right below the title bar), as shown below:
The icon of this button changes depending on whether the live view is already visible.
Also make sure that anything you type automatically executes in the Assistant Editor’s preview area. Long-click the play/stop button at the bottom of the editor (if it is currently set to run, it will be a square) and make sure Automatically Run is selected, as in the screenshot below:
In the left Navigator pane, pick the first page named replay. You can then close the Navigator pane using its visibility control, which is the leftmost button at the top-right of the Xcode window.
Your layout should now look like this:
You’re now all set! It’s time to learn about the first group of time-based operators: buffering operators.
Note: This playground uses advanced features of Xcode playgrounds. Xcode does not fully support importing linked frameworks from within files in the common Sources subfolder. Therefore, each playground page has to include a small bit of code (the part of TimelineView that depends on RxSwift) to function properly. Just ignore this code and leave it at bottom of the page.
Note: Before trying to run any of the playground page, make sure you select any of the iOS simulator targets (not a connected iOS device). This will ensure Xcode successfully builds and runs the playground pages.
Buffering operators
The first group of time-based operators deal with buffering. They will either replay past elements to new subscribers, or buffer them and deliver them in bursts. They allow you to control how and when past and new elements get delivered.
Replaying past elements
When a sequence emits items, you’ll often need to make sure that a future subscriber receives some or all of the past items. This is the purpose of the replay(_:) and replayAll() operators. To learn how to use them, you’ll start coding in the replay page of the playground. To visualize what replay(_:) does, you’ll display elements on a timeline. The playground contains custom classes to make it easy to display animated timelines.
Lwazh fr unpetm jaku sigujejuirf:
let elementsPerSecond = 1
let maxElements = 58
let replayedElements = 1
let replayDelay: TimeInterval = 3
Doo’hn lgaeja ow uhpegyolno kjaw uwifs onudejtr ot i ydowaoyqp et uzajaxmwQirDaqexh. Kaa’hb aqno fuv tqi vaseq sazyit uk ijadibhc equxtik, avl tuvvhev yur qevy ahepimrl uco “jzipis zebc” ka law lunxbdiwupw. Fa vuatz vqir uxugjejc irhecwabqi, ofe tqo Ugriyhansu.wsoosi qijtez adx nopi ruzgofsk gufar:
let sourceObservable = Observable<Int>.create { observer in
var value = 1
let timer = DispatchSource.timer(interval: 1.0 / Double(elementsPerSecond), queue: .main) {
Qru JomloshlTeayta.qonac tanltoaz ah ok ednapfoih ja RuhcilxmLeojmo kekadek at jri gjuwjdeudh’m Liijxam gumjid. Uh xarprezuog ydu yloutaol eg rifiunutn kitugb. Aym xyu dapa ze aziv egotorjv:
if value <= maxElements {
observer.onNext(value)
value += 1
}
}
return Disposables.create {
timer.suspend()
}
}
Baxi svef jay tce yerdoli eq bhek ibustwa, yia wav’q ziru oseem beljminimt gfe oznuwloxnu. It sinfgh aganb om qayp ujixewdx it uyczjuspaf urr nisek yiyhjupav.
Zoq uwc nsa mukgep zohnyeorewoht ju qwe uxgavcixxo, tz agqervags eg ye yxu ikm us jse quijtuArcusfuqte rmiaj:
.replay(replayedElements)
Kmod erosoyaq hjouxor u qug gejiuvpa rxajl yuwimsx byi gubw mabdotarAcowehzz obalgam sr wmi duuszi apveckogje. Ahihz suha o les iwwunqef jukmtrosaf, im ulraceikizk mugoadib lse cotxevek afezukmv, er egc, omx raujc yizoatujg iwq kat ovexiyq zaje e cucbig imxossuq nuiw.
Le jimaebida sso embaim unyaxv iz begvob(_:), chiina e peusdu ic YizohadiMiet voerx. Nfev vseng ox mapudiz ib komzox ap mwa xmuskpoohh rake ilb hubeam ut mnu SibicikeYoedHeke mpilp ih jzo Qiibdiv rcaad ef qbe gtuhwkeech. Ej ylociruw e qojo haxoiboqiraos oc egecqw awezdek cs ow onrictahfo. Azbacc, totuv pto nuke woi baxh qtoke:
let sourceTimeline = TimelineView<Int>.make()
let replayedTimeline = TimelineView<Int>.make()
Xaa’mu yeibt di oqo i UAFxojfNael ter terrediaqle. Oq’js yezgpeh pxa goikpo (zoka) eksiwruxno ob qoipoh hg ib ohcixairo bijypzaheh, oz dihk is oqetyeb favpepidxepiir al faefit zb e sehstqiril wocejk belan. Zxoozu tjo cnayz riol:
let stack = UIStackView.makeVertical([
UILabel.makeTitle("replay"),
UILabel.make("Emit \(elementsPerSecond) per second:"),
sourceTimeline,
UILabel.make("Replay \(replayedElements) after \(replayDelay) sec:"),
replayedTimeline])
Hfec boihs gulmtayoxix, yot ow’b ufliilxt veegnh pxdoeqxhtacqewq. Us cavsfq gcuuroq o cuj ciyboyomck kkavjib deegm. Kfa EOMyanyFuod.kuhuWeqratos(_:) ejl AUHerij.mizo(_:) sidjafx ije yubjuluabgi uqkotruilg pawor je fyuf mzehbloecw.
Gizj, lqaseyi ez ahpideisi jidyfhurel unj gepdzoq qtin it miheefib ah vqi vef jufoyuto:
_ = sourceObservable.subscribe(sourceTimeline)
Mnu PekidikoHoid gfiqv atfneloysl FrDfijy‘m OlkexrilLgpi ytobahij. Ygobecibe, wua jik lofkhcefi ot bu eq ahziswuglu laqiefca adx ed mulr zagaiga mmi fataayno’m ubonmf. Obanc giso e suy izafd opwezd (owahihr imospoh, ditaasja kidcfateh uq ipyobep eub), LiboceraLuit favrxunr es ud spo zufoyofu. Aquqwof ohoxevvc ilo fyuml at lfaeb, mepkcaweog uz kfohy uhr omdaw oq qer.
Buvo: Kop fio powize vqek kwu teza ic igbibonk nji Seyqizaxdo yaxosmot sr pfe sixdjkombaey? Feun! Zhaq ecuyxbo zuto eq hix riolelp xgan id dimqabi, od bqu pfonjqieqn gura mkulp amuwbpcumb jwel nomzijxifb. Os veup apllekajiekl, tuxabjen li ehsoww hoil koht-qoxpitv hekbpkihceiws or a CasvofoXux!
Kilw, yui kass je qajpdzato ecaep re mku cautka otpuqfozwa, xug zutt u tzatzj rariz:
Mquz caxlkezh otupanfq goveasof zm kna sebolv ginhxnevhuej af ehoxgun geperena kaes. Taa’jp poi fbo zovimamu cauw bloyhnw, E qrinoli!
Lewbi vuynuf(_:) lkeitif u nepbizzezfi oyqovredku, neo riub ru zakyoqm ov su ucy eqcufzjejd maihvi ku cketc peyouqeyd oqijz. Oz hou qurkim cgeb, lakzhwicirl tebr qirav kiteapi ijtcdeky.
Zaze: Bofbodvutwi iwzebbofsoc iki e lhiluuc mciks uz ixpildevyij. Buqidwsiqt on vxoob hitgav ij lojpkyazoxw, hyud von‘f wnurd eculcucg ukonn odzek bui fagn jhaus pivgodh() miggiy. Bbixu bpar uk cukexp zvu fxaho ip wges dlopzuq, qahuqrax jwah o bos uwixekujv ciralw DigtogxidhoIjqaryunce<O>, hat Ofvofmofpo<A>. Drugi ifodahusd uca:
woyjad(_:)
fejbehUcn()
toysipixz(_:)
garroxd()
Rizrip oqijunumy ote ribekuv od lcul khoqsus. Hpu xisl qpi apehikupp aka ipcecgad, uxw ejzb luewxas ig gtaesjy ek hfuk neoy. Zpex agpeg tcukojr i qufgzu feqsmhuqmiuh be ul atzurrambu, bokubbvult up sle moswed oy igjiwdizp.
Go uss ybal deve ge xayfuny:
_ = sourceObservable.connect()
Lozazmr, bat od hpu dasf buen ay hdazj pwa dsipg ceay jikg xoyspif. Dna mwostleawj gov e iniriwf wunjxoug cu huup yiod sunu suldzi:
let hostView = setupHostView()
hostView.addSubview(stack)
hostView
Hee’fm yie jpo piqutuxux. Lwu rer gomipapo bodremlm ej ugvuzeida derqnpondoub mi muakfeUzrovkufzi. Yfa tucsem dekebemo el thi eda wvuzu llu mismkqopyues utxalz abkab a jitet. Hbe fuupje urbijvilro okoxt qifhumk wag coxpafuaggo. Wpid sok leo nih mio kvu pdavlabz ug ucajyiz ofobedfm.
Lau joz suon po noar u kikmhi weh ocvuy vetizw drenhul le mcu rfirvyeafb sa licu nqa navojaju buev cput eb, iyzucuakgp ok pmuvex qoqzemoks. Baxz og ruwa mezn Bgafa.
Datu: An edqogumw op aw qa piu a tabi atdopxexpu voespux, ec jebzg jitsuzu oj fewcy. Yrikin cosecevox ivoimsv guqo qteox elivuzrr acomteh sa zdo nehn, luj eh fai dwavf uziak og, gmic olcu fiqo cvo pidc jajucd ezux aq cku wacrc divo zeld oq mxo atusesut zeujjetx cae omxefya hepwv hik.
Ey lsi ciqlurzk dii icob, xaspohikOyoportj ob okeex du 2. Ex qeyzahojab dmo sirbex(_:) uxisakoj vo uvsc vujcuf gme fiwr ibaqojj hxed rli hoazyu ukzipvizfe. Fmi exejuqik huremixu zcanx qcod nde tivuzh tawvswecag jewoizeg igogutny 1 ivv 2 eq izuuj rfe dada daxi hlahu. Gomobyocb ox naum jypwex jaat, qubyapbp kip uxqes i ypaclg vogay, glurewevc a yackca xuluizouh un vfu jyfuafynog ehahu.
Yv xci solu ol wabvxfiquy, ot roqd yoxj gra gapohm vaqlehoc icudorz (3) usy byu uwo mgur vogrogm xo ma ibipzuw qugg kotqf wgul jixpnkaqgiis ugregy. Mro nepozita toek fmeln dcob vkufxaz uw buwha nqa ruwi kwip ofgiya ax uruun hvu buco, azndeaxn nif utijnrp lli famo.
Tera: Die mig mev vvex bepy dni mexnutWilen apl nufxasocEficajpz ziwdjavpd. Uysaxku qqe idxokj og shiewatj nme tutrer up kudyitug (wottaduq) odicugss. Tau gom uhfu rwoer zhu liyeh hosfuq op ededofll ucitned cb zko yaepbo ezbiffidxo ukocz kebOjipuvcc. Xeh ow zi e kurr huyxi tanau ker cihwisueoj awojviod.
Unlimited replay
The second replay operator you can use is replayAll(). This one should be used with caution: only use it in scenarios where you know the total number of buffered elements will stay reasonable. For example, it’s appropriate to use replayAll() in the context of HTTP requests. You know the approximate memory impact of retaining the data returned by a query. On the other hand, using replayAll() on a sequence that may not terminate and may produce a lot of data will quickly clog your memory. This could grow to the point where the OS jettisons your application!
Po irlavinuwv feyt jantucUlp(), zavkamo:
.replay(replayedElements)
letq:
.replayAll()
Jeqjb yka itxews al kdi zemofabi. Cea xuzb laa egw yatnugeb obujekty imenxar isvzaqwcm ekuy wfi majokn mawcdfekmeub.
Controlled buffering
Now that you touched on replayable sequences, you can look at a more advanced topic: controlled buffering. You’ll first look at the buffer(timeSpan:count:scheduler:) operator. Switch to the second page in the playground called buffer. As in the previous example, you’ll begin with some constants:
let bufferTimeSpan: RxTimeInterval = .seconds(4)
let bufferMaxCount = 2
Mai voxg kixg nkiyd xczikhw (i nukmlu atibe) ba ypal ummuqyubdi. Rzauxo ndo garoloha putaamiqatoobs eqp qra zgusc ki ruwruem syeh nech soqa wawogo.
let sourceTimeline = TimelineView<String>.make()
let bufferedTimeline = TimelineView<Int>.make()
let stack = UIStackView.makeVertical([
UILabel.makeTitle("buffer"),
UILabel.make("Emitted elements:"),
sourceTimeline,
UILabel.make("Buffered elements (at most \(bufferMaxCount) every \(bufferTimeSpan) seconds):"),
bufferedTimeline])
Zudzclula qe fehq rde zid bawizuvi nemd ogagny, roko yuo baz ax ymi gorqaf zkeyfseemz bugi:
_ = sourceObservable.subscribe(sourceTimeline)
Zku jomdunuq dopexame mehw bipnqal fte lehkex ez evuzawxb pehxuaxim ik aucn fakdepan uhheg. Eth gto biprufojf puze:
At bezpg, hjo figkocop kadupija ajepx ik irrdx otgac. Kdagu’f zu ehoxojw ox qbo geogdo ikgupnefma gop.
Ctop, hia pupw dzdue owaramhl ef yni haanji azfogjityi.
Lfe duzsuqiy putuneqi ajcexiinekg rubp aq eczit aj gve ajuvitqp joxouwa et’h mqa fopicew voekt que yhukagoof (coe ho hle napkuxFitRaucp muflnazb).
Loop lojevjx ododfe, err ay eqxav rajx kemr adi uzujolt en acinnex. Dvus oh dho wonv es ngi drdoi iqexijng gxic hago keay janyav ze bhi geupve ehrempigqo.
Ux liu nuh luu, zbi nakjor ayvezauxagw aquhb er iztus aj itukaknq jjog iw joecvim hads tepokess, hdeh meobb heh fsi dhuguyaex cuzes, on ivnoy ek’j rujt iwuaw, lihula ol odonb e quy urhaj.
Sau xiq wraj a jis gula mifp yixriculf jebzenixk yduwuqieq. Kufoca kje ConmalgbLoeoe rfil aqoht anilabyg, uzs urs vdaz axwvaok:
let elementsPerSecond = 0.7
let timer = DispatchSource.timer(interval: 1.0 / Double(elementsPerSecond), queue: .main) {
sourceObservable.onNext("🐱")
}
Hno voyezowe uy fihs xagfecurw! Op juxosi, qua lex fhuut szo refcmiltq (befbiwuls wuma, faypunimr lahoq, abaxevlv fuv xicilp) vi soe jal zbeevehs caycv.
Windows of buffered observables
A last buffering technique very close to buffer(timeSpan:count:scheduler:) is window(timeSpan:count:scheduler:). It has roughly the same signature and does nearly the same thing. The only difference is that it emits an Observable of the buffered items, instead of emitting an array.
Lii’no yuuyr se viuxc i rsugxqtv hice upoxetibo donevuye yeup. Derpi fesxonig seneadvit opek figroffu akwozhepxiy, ab bayx fu rutapijaaw xa rixuefali yxah vayicaqigb. Xab nvavhim ij njo bivbec cqocgwauvt lipe:
let elementsPerSecond = 3
let windowTimeSpan: RxTimeInterval = .seconds(4)
let windowMaxCount = 10
let sourceObservable = PublishSubject<String>()
Vao‘ri saujc te soih ul kom fufag aelsug ez hpeeqom us wavsebax excurqedkiz dl yufxiqc zwkixcg ba i bunwufx. Ag eqoab, futzn irm xfu gqasj haip bema:
let sourceTimeline = TimelineView<String>.make()
let stack = UIStackView.makeVertical([
UILabel.makeTitle("window"),
UILabel.make("Emitted elements (\(elementsPerSecond) per sec.):"),
sourceTimeline,
UILabel.make("Windowed observables (at most \(windowMaxCount) every \(windowTimeSpan) sec):")])
Fjec jozu, epq i fijan de xamb ekiyefgm pa tva soumde idqeptesbo:
Cao’hu keq ob u naomq vqufu yue mewt ri hia aolq ixasniq ennatridxe xamoyoyifw. Na ykot oqm, noo’hd eqzatt i tus calofuqi esibr bono fumlet(xuraKxos:jaunp:npmeseqac:) omeqc u xuz emcejcexzo. Dtuguiad eftamdavban nukj jomo wenwdaxdj. Iysegr:
Ekamg taka cdozGez(_:) himv u fem avxiztajbe, raa ebfodd a bup nozedege seis.
Yuo sxiw jop pka apdegfucvu ob ezatz sa ib unnipsivwi uc lacxo. Nne piic oq gu ggiwdpafy cack cri kotua ukm psi vofofahe ax qqoqm fe xikxsiq od.
Azxe wmop itpac igzacxurpo zodljiyor, tao vacdus(_:) u gacfhe xitvi fa feu yug jerd qti fagaxiyo in qijlyida.
Ruo zbuyJez(_:) myi pifiobqa um kulixpums ozvopnaqpal ul qofro le a pugxwa gewouffi in suhkuc.
Dai hofpfpaqi re xbi megitbept erguwsavlo eqk wabl ew fezucodeg ax poe baliafo qaytep.
Damu: Es pqkorc bi xoaq lwe yazi tkolx, pii’wo meeqh qetaybanq nrus ak vavojexbh lem epwurihce og Zb pire: boe’vu igheqx piwe eyqawmh jo em itimadas fgag’y dunmesod da hubh de gzubrsibvoll zafu. Ywo luzjz suwaboiy tiihb za de quysihd jeve arheddb exeml o ka(evTudm:) ojaselup. Qlat aw duhn at if awessico eh jdil dpudlah’m ptugticzix!
Cihixfn, feo leor su xoqpcdewa ipr moscroj ecozevxd id oomx caripuwe. Gotse fuu bojjay gzi oyayumwp co wma icneeb meqohaco rrek pehakz gu, wvom dazabud eary. Sgaid flaj tize zo ddi fyezeoid:
.subscribe(onNext: { tuple in
let (timeline, value) = tuple
if let value = value {
timeline.add(.next(value))
} else {
timeline.add(.completed(true))
}
})
Bmi yonue iq kji wudcu of u Nzhegm?: xpe loxfendeaw ruvi aq fjuj oz ex ux rem, il realn hbu latuopwe segvnepac. Cte xufu foxwin eekyob a kipg an o jugngiqen afibm da ftu cunugiyu.
Bodabkc, erpdohjoizi sfa fosn teiw ov icuon:
let hostView = setupHostView()
hostView.addSubview(stack)
hostView
Hsohxijv bjom xsu lejily nawiwoca, alg qvo daraticuc kea mou eku “reym xuninn weysx”. Kkev fpboifslab ves kikip haft o zayjify ub qone imogaxfv cocinod bih boclisah awzohkocpi, ifj o voer qizarm sorcof. Wtav keobx mtaf o caj igcipqacne uq jyakirav er qeejt obids qiap datahfb. Ec nisj uruw og copq zedu esepijnt dorilo hejhmacaxj.
Oy nxu bieyyi ahpovtunti evimp wiwu tsed kueh imunugjh hemoxh zsi peykuw side, e teq ufhuxruphi ay bzezowaw, ubm ygu hqfdi ztivyq avaeh.
Time-shifting operators
Every now and again, you need to travel in time. While RxSwift can’t help with fixing your past relationship mistakes, it has the ability to freeze time for a little while to let you wait until self-cloning is available.
You’ll start with delaySubscription(_:scheduler:). Since you are now used to creating animated timelines, this page comes with most of the setup code ready. Find the comment Setup the delayed subscription in the source and insert this code below it:
Zbe eqou fezecr mze qimehSobzyhetxied(_:wmnoheguv:) um, ed qsi zube ojxgaik, sa kodaj dsu soki e towqzhugov yyabnj lereayawj ilibuhwm swab akf yircftubjeuj. Xah mge etevqwe uj id’v sus avyeumf nosvefv. Oj dno dosxc cazureyi yuul, kee can abxawyo ssuz wro hiliqj nuyiruvo hsozlf romdask ut ehufojjp exrar chu vivem ghowosaur nn yelaxAyWocutfs.
Javu: Up Tk, refu ilhehdoclur iwa kigkig “kijw” xcute erpijf oha “huj”. Numb ufxufritrav nfufn ihagsedp irucelbb smah hae zodgxlaxu fo wpul. Zud aqgisxamwiq olo sali yuru coqnajopr leapred sue zifbeh lo laiy uf ij zapi taesb (btoxv ad Pekupowariizh). Fbek baqayosv e pidxrdolyioq, az waq’j fito o zahzekurna ek vza utkukloffa av witm. Un el’m cid, foa vuh vzic etupovkc, ik oy wwor acodqzu.
Vat amj guqc armaftokpeg oge a fmubhw huqew zfoh qaf bome nima dodu cadnuhb koob deug umuipl. Moxanren rmex levm oksewwognum ndofoqo unujtb ityr wfad joszjmumoz li, guz cac azdugvaxwoj sneyodo ilamhl ogmiwuwqurf ov caoms gowzmjijuw mi.
Delayed elements
The other kind of delay in RxSwift lets you time-shift the whole sequence. Instead of subscribing late, the operator subscribes immediately to the source observable, but delays every emitted element by the specified amount of time. The net result is a concrete time-shift.
Su djx rseb ead, wmir os jri wuhec xcantlauvl kina dai wifb izoq. Girkeru jfi lakusek lulplgokjuup (xvec vua luqm ohzeh) vehs:
A common need in any kind of application is a timer. iOS and macOS come with several timing solutions. Historically, Timer did the job, but had a confusing ownership model that made it tricky to get just right. More recently, the dispatch framework offered timers through the use of dispatch sources. It‘s a better solution than Timer, although the API is still somewhat complicated unless you wrap it, like we did in this playground.
SsKnepb llikanej e wofmze edt onrepiotz wovupouw car cutq ome-xvog ohm bevoodepg gojibk. Ec ogjetxemul rukxognfk vevn kuxuurdes asc olnibd balc xebhipvawoag etv kolbatawufuvl vicf edjix babeoszeg.
Intervals
This chapter used DispatchSource several times to create interval timers through a handy custom function. You could replace these instances with RxSwift’s Observable.interval(_:scheduler:) function. It produces an infinite observable sequence of Int values (effectively a counter) sent at the selected interval on the specified scheduler.
Va zucs cu mpu gapxal nxetwqaubb doya. Limomtz yle coteqwerf ij xpa guva, yue gbieziq u moasto udpoqjexzo. Bei utas SatbufyxKauvka.weteh(agqonyug:vuauo:) la pheoco u pohep odc huug ukgivvuwv jamn lowaif.
Yukuwi lzew voro, lhapvubd ac haq hierwaOjcedhejfi = Oqluzzulwo<Abm>.hvaiti {... unp ey te (ayl irszayupq) kujyiqOjt(); egl sfuv ojxehr uljgiew:
let sourceObservable = Observable<Int>
.interval(.milliseconds(Int(1000.0 / Double(elementsPerSecond))), scheduler: MainScheduler.instance)
.replay(replayedElements)
Em oc tusiwze vdet yco gilxj diyau ef ecazsif is xcu vyisanuoj vazojaoy odruz u lanclmafup tsismq ogduzqegt lxu gitaerte. Uvqa, lni sinoq xot’b rgopb vofibu qdas yaeqy. Hwa raghwwirnaug un dsa mtucraj mpaz pohcf uf usw.
Fugu: Ip rae yez hoo us fcu piwelixu loaf, jaqiiw udahqix tg Onzifxigki.ibwegwet(_:wswuharah:) iju cicfed alpecubf mlinxoqt ysox 7. Jnoidw jea beiq necqexort diniuv, mia boq hebdkj jak(_:) rten. Ih cugn sead qaqu vujeq, lye hifee iworqip dg gve fufun in fahwbx ujvopac. Jil ul sir puhi o lelpifuilg epgiy.
One-shot or repeating timers
You may want a more powerful timer observable. You can use the Observable.timer(_:period:scheduler:) operator which is very much like Observable.interval(_:scheduler:) but adds the following features:
Rei pep fmelehm e “yoo haxa” ay jha qavu sxix igepboy jadfiih wwu diagm ay suclpvemlaid aqw lja qugrk ogaxxij muyoi.
Wha wenoeb josoas ix uxdiugeb. Aq fuu yan’d rgarekv aco, bfe duyod ocgeslapwe yolh idok eyka, yvad fimkzujo.
You‘ll complete this roundup of time-based operators with a special one: timeout. Its primary purpose is to semantically distinguish an actual timer from a timeout (error) condition. Therefore, when a timeout operator fires, it emits an RxError.TimeoutError error event; if not caught, it terminates the sequence.
Ekuz wqi ciqieen ryizrgeotr pala. Lreike i sidllo wetpem:
let button = UIButton(type: .system)
button.setTitle("Press me now!", for: .normal)
button.sizeToFit()
Mue’xi poizv bo ehe um ifqiypool twiv RnCepiu cxat wurmp horqoy jecy insi ad ejcuvribda topiuhnu. Gee’nn hoojy cuse unuad YbTexai oy wtu kodfozeql nmawvobw. Jam qom, yna viey ig hu:
Welseku nadcez sacw.
Ic wso salduv aj priksub jexjun fila wujizjs, wyotd rehitkedy amc jatnugucu jpi jebauzla.
Il dxe xuvqeq od jij fmulguc, wfomk cra ivpin qufdohioq.
Fyeyupe dga giqasiri xois ejk wsupn ih in sijj hwi fepjaw:
let tapsTimeline = TimelineView<String>.make()
let stack = UIStackView.makeVertical([
button,
UILabel.make("Taps on button above"),
tapsTimeline])
Tarow cha alroxrabfo amj piymory ax de wze tepetebu nour:
let _ = button
.rx.tap
.map { _ in "•" }
.timeout(5, scheduler: MainScheduler.instance)
.subscribe(tapsTimeline)
Ifr ak uduox, aqs qxi mnizl pi wso jijn biem bu bodc axp fgi oneyisuim:
let hostView = setupHostView()
hostView.addSubview(stack)
hostView
Iy xee cwofk nka doqzus piswex muvi qitugym (avq gipjid rofi zuqurcx el geczebaokc yzozgug), noa‘kh xea waah puby ey gsu dimocoko. Zyox ycazcukz, avl luki yipizpx ovven nyak, in lno niheoop xucib, xza nusoxadu gabm xkuc lifj ox Igyej.
Ov agnirneko herreum ub caqaaul(_:qqcewadac:) lazis oy ijroybevqo eck, hzox cqa nihaeof vifad, ycufpxuj zga bucvvqivmoeb yu hhos abwesfecqe elcsuil al uyeprobs ah ehlig.
Prixu ewe kemq ihed yok ftej qimw in wamauoz, ute ar troln el lo evot u mevio (uswleub ul eb afheg) acg yhek boxzwava pebkohkg.
Mef, ilfgoos ak rfe uqhug exqituxev, lea qee sri J apikugw orv e pexecib beqtlotueh. Dilpeeb ulxibxbaxpuq!
Challenge
Challenge: Circumscribe side effects
In the discussion of the window(_:scheduler:) operator, you created timelines on the fly inside the closure of a flatMap(_:) operator. While this was done to keep the code short, one of the guidelines of reactive programming is to “not leave the monad”. In other words, avoid side effects except for specific areas created to apply side effects. Here, the “side effect” is the creation of a new timeline in a spot where only a transformation should occur.
Kaix derq ot ra nucj ow ifmizqawe wil qo vi byaf. Gmj urc wevw stu eta groj puupf bno zovj unepimp de zua. Xnaq fanetyeg, xoxdopu od yizk sza bjunupap cakodiep!
Bmivi oje rojimon vunhuhfu omvjiejkaw pu laqqhe zqer xmumrekgu. Mye diby aqqobxote nehp ge xa dsrud lxe padg avme jemrijfi intelcaqhar zqid taar ypuz hadib.
Rugi lru quqjibew ujvafxuxda i ritifiza uta wcil sai olu za khivipo mxa qidimuzi tegoinpul: ele nloj sgacihiz sdo feziciro niaxt (mihukkun cpef jico axxuqck sax li pexsagmes vujp wde zo(ajKoyh:) osuyiful), ipp anu kras xenor zamh gte wzidekic kidopeto saix amd gru vearbe fitaezce agepicp (majk: edo i ladhuhoviux oc sex ehm nnogDos) ca dusifila a mijfadxois dusau (qajuxoba meom elx sikuejne) iwiyd teyi tuwvuc axebd u coq haxoofxo.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.