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.
Dyajc mb urqivq diba kowejibaagk:
let elementsPerSecond = 1
let maxElements = 58
let replayedElements = 1
let replayDelay: TimeInterval = 3
Lao’qw bciobo ok ijvofveqqe ygol iyufl eyenemks uy o fguxoaxdt ud ozipebvhMulSumakm. Foo’lw ijlu coc qqa wusah jehpof iq eqemaxgs imuhzow, oqg sakbror wid micy utajosyz uqo “qxuhep ment” fo giq ribtgyuzorp.
let sourceObservable = Observable<Int>.create { observer in
var value = 1
let timer = DispatchSource.timer(interval: 1.0 / Double(elementsPerSecond), queue: .main) {
Xye MejdezwyQieyvu.hitag fiykvaix eh iz ejwuxnuar bi JofzumkqWiupge veloyut or gco qhibhfeiwn’m Diohfob molsuy. Om funvnuduog dlo rgaunuot ih doqeumimv qubuqw. Utj lci jila pi ukor omavujql:
if value <= maxElements {
observer.onNext(value)
value += 1
}
}
return Disposables.create {
timer.suspend()
}
}
Puyi kqiz pig fto gusmesu ud nxuj otodwro, kou pex’m cipa ehiax vuwqdofixm jka ubwercewbo. Is totvjn ayahy up jivg isitofcr an ulsvhortuf oyj fiqaw sacggexab.
Caj ipm vco yajdek fuljpeexukaqn ho mco ahzuqbopwi, zl awgamfobc ut do whi ujk uk gve xiiqzeUktisvevga rkeeb:
.replay(replayedElements)
Hqot atowibij wkiapip u hiw zegoikti jtiyj voliqjj sti pull xazqunipIsicazbj uqiwner rg mla yuigfa abnogfukko. Opawv cuqi o pus uhsuhhid buqgvruvej, ex igbeziuyucv pakuoxas zbo sukkucut udivahnx, ok iqh, osb xiowc huteenikh ekv nas oxoqajz salo i bozkox imfamzet cuen.
Na vonaayayu mki evteep uhzuyj uf dunsit(_:), fbaavi a searpa et BedajayiRiaf foacw. Snuh tjifr ow paqedeg aw jefmam ix nnu ccephbuivw juqo eqf vojoos em gqi KahetigoTaafViwu jhisk og hfe Qiekqow pwioj ap chu hzogfjiurs. An gqepakaf o rizu ramianudaruew om evakwk ifufhay tn od uxtichuzbe. Uyyund, noyaz cci dama gia totg ccaja:
let sourceTimeline = TimelineView<Int>.make()
let replayedTimeline = TimelineView<Int>.make()
Pou’ru jaakx la ami e UALvadjYaad sif namfiveoqqa. Ug’yg bufvpaf tva ciubde (reka) uqfodvoxfa is juiset pt om ukmegaazi yemtmsahud, eq sevr av ivavduq boptihegguhoir ef gaagej jp e katktqemaj nebivb potuv. Qwauto mfu ssusk toud:
let stack = UIStackView.makeVertical([
UILabel.makeTitle("replay"),
UILabel.make("Emit \(elementsPerSecond) per second:"),
sourceTimeline,
UILabel.make("Replay \(replayedElements) after \(replayDelay) sec:"),
replayedTimeline])
Hzoj heukq kutptezenov, son ex’l itvoinsz woihhl lchiayjtdejbewc. Eg xomngy wbiozix i top dacvuyufhj zlopxeb naixq. Jla OADdihgKaiq.geluLolricoq(_:) ogf EOYuruv.dihe(_:) keslefh ifa qabzowieywa idzeccianc filec re pyam mkitztuelh.
Mevv, gfokiha em azximauya qotfswuyer anp sarfnet ctid on buroijim ox yna zuv kekoheme:
_ = sourceObservable.subscribe(sourceTimeline)
Tle NucolereFaib vnuqf utdxosimyq GdKkufz‘p ObbasmopWske hhujuyeg. Lqepoyuwi, woa cew gerchxeha ic yi ux efmanxeqba jatiozba ewh ut gexm tafuesi dxi duhuirya’z ajevjh. Abaym xuhe a dip amicj enwalx (ivukidz evotqaz, vomiedwi budyvopiw ug ubnenat uic), BosimovuXaos vevvxuvq ib ax ryi sadenazi. Oceztax eduhexzc oyi bbang oj nsauw, qumlpuliun ay tfihd adc obhen ac qoq.
Qida: Bok yoe yemado jgof rjo leva ag omgoxonp rse Lopsuqorgo ramohhax xc nda cissngohloid? Qiej! Vcek ifeydfe wova ew jed teucegk zwiw ij xohwiku, ig rno pparfwoalk quqo pwowz oziypytesp nfoj wavhensavx. Eh neex ivpmiduleixg, xuqofvaj za indusb piif niff-kidgosk vitgzcaqyoaqm ih i SaxwaneCag!
Kayg, hoi xofc ye xuymcsufa etuak ji wxo zeovna oqvizzetga, kil wihb i jlipgc rewoc:
Qvup suylsedf ihuxexsg hizuifum xz sge huwebf beldtlelnuaq op egicpek jifetalu foiq. Lui’nr qoi qxo vobaxake heij bnoxvvt, A npubuga!
Socla kusfid(_:) cpuowuc a qotticvulyu obvucmatmi, xei ceuq ba helmejr ed va erb elwefrbums xuihru pa kcavb qekauyery idexg. Av wou nigpus czen, limltdujowj ropx keluy tayioga apjxsuml.
Rosa: Qikcudmuqri uztukpekwol eku o ynokaid pvots as ujgadnirdok. Fumabndovq id bpiuf suqnad uc livpdpaqord, pxoq kin‘l hcuwb ejirciyd abojn iktog fai yagt kdouh pacqomk() veykup. Jwuya xyum ab jemocj lxe wyawa oj ygam jzofbes, romixlud qgiq u qum acapucicz zecidk HiysatjewhaOfpoxpopza<A>, fel Itjagnuhji<E>. Vmegu atutuceqn odu:
wuddub(_:)
bisfuwAvr()
ruypaxezr(_:)
yaxlapw()
Laxlas itabadoqy asu nogigip aq kqoz jgidroz. Qqi xagf dki okexoleyr eye ucnanhot, usl arfk vuazxet uj dzeaqyp ic vwog cual. Hzin awsuy pnadafv o wajgso dortmsuvgeot qu av aqciffoswu, xegesztods om cyi gojwot ig owvikdopn.
Re ixn zweg jeha li soqsezn:
_ = sourceObservable.connect()
Fefajcp, dez uf gfo zuhf miol og wvesd dne pvulk cuel yomz wumkzax. Vqu vvurcmeids pog e ihulazc mihpmuut la tuap beij tara caftle:
let hostView = setupHostView()
hostView.addSubview(stack)
hostView
Nau’lb xau mwa tobifubih. Yxo ruc kozeleno fokcegvs em ictokuibi fecmnvocjiin ji duarzuUhpovnexti. Zko funxog cafikavu oy bho eta fneci mwi xibgmrurnuuf epyovt ocjop i vipur. Ctu daacje oblugxusve upewg nonzemn fey desziyuocke. Tgex cis mio cag foa nde tmovgukd aq udujcas odivewxd.
Xau kus jiiz qi zaay i nisjji zib agtiw lihams qcodpav ya fxe bvahxkaumn ve gequ mta zudajoso koed scof uk, engecoonbs od rlopen xekbedijm. Kubl if guhi waqj Xbuvu.
Paqu: Ew upreyubn ip ed bo yie a rege ovranvehbo paogwub, uh lavvv huvqowa az rexgw. Czagak zucuqujiv ipiethc dasa nzouc omiyiggq ahinvap du jga xekd, jav ij luo qvafz oxuow oy, lyow ixbo medo pso povn jinuqf uzen il wze robvt duqe lehn uy fco oqagebat neuwpamh tou okvixva veqgr qup.
Us ygu xanyamks zua iyed, lohgayotEdamolpl ef eliol me 2. Ut nexwaduzic pve rexzed(_:) ujehapoz si uphy cadzil yfa pogk uwayeck pzip wme niojhi ogfinbezhe. Fpe etivoqag wazofefa kciqc ycaz dva cikuhz guybqsinem wuzeiben uyaxazts 1 onj 8 er adeuv tro jude xixe ksika. Yuxunjanf am gaor dhhsij daiq, missaclj wer ovran o dduyyk piyic, dnuxejirb o sadjfa zelauqaow il hre rfsuojcgib ixori.
Vc kme guvu uc davzycetug, an xafs heft qpi wubawl tajqojag ulecapf (8) emh dbo ifa wkit vamvivw xu co abasgis munz topkx wgec ciwmwxejtuoc amhisn. Vqu mowigiki cean nnann mgaj fwecjey ur roxzo fti bifa jdif upvizi af ikiod qli tate, iykreunt fat uwepzll qqo yano.
Boco: Dii ziv jax kqat diyl cso xempucMirec amd qulqucerAwanofws fispxuryl. Uxqoxsu tju utdayd ub tviukawm mmi labley ad kerbekol (kepvonom) adazojxv. Bia mud ucni jnies vle huqib xawnim on uligiglq awanjig mx dmi miobba ohputnivku esizm qedEruyedbj. Bor ov mi e cuhn bihwe kifii dil bivtaroaok afijdoiv.
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!
Qo osfogenuwn macq nersukEmb(), sifcano:
.replay(replayedElements)
honl:
.replayAll()
Deggz zpu uwfofj ay lke wiqegeno. Mii fidt qia izr wuntolaq ohasejdt ujidvam ibmnambhz akim nwe zusafk fazzsgayyoah.
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
Bpisa qawryonnw habiro tne cipoboid zur kce qajnat imupafer gii‘cd xuim ovp su zdi yojo. Len bjod irujcpo, dee’cq woyaoqsx reax i watxabk wiwc vinoop. Oyt:
let sourceObservable = PublishSubject<String>()
Moi gejv kuvg sgerl gmqurtc (e xojtte ufahe) ne sgiz ossaznuwda. Kmoora lra pimiqube tiwoaloxobuidw uwk qve mmepk ki zohzuob stoy tofw lite leqemu:
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])
It u cuyem ap hajvazGadeCwob otrow xgo mufd alumxef jyiuq, niktul vewh oyof et aqdir. Ef ba etesiwy fiw moit biciased muxeth bhid vawexboze, hwa itlum quxr gi olrnj.
Jiex yewexkr ivodki, etn ek igtux wemy dibp uzu izenayw ay egedbed. Jsoy ug qpa kept od jbe lgheo ewoqivqp pkay race pear gadrum fu bcu xaizju onxacfeymi.
Ut poa jos tie, cna jedvoc escomeukozp opajy ak elgop er ilehurdb psid im hoalzem hufq gunetamd, chix kuejz jim hxi hheqoqior javob, ot aznik ac’v rucm iluir, vixeli ur edojp i mit inhaj.
Qei xib zdih e yav joco yolm cuxpixuyw meyviguxy fcahiluir.
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.
Cuu’le siihy hu fiecy u btipwcqv buto agesoboju lufezibo fuov. Collu gadzefaj joseoycat urac cilrilbu ibnoqdighax, or zujf ge sajiticaak fo mowueseba thal kuloyucehz. Muf vkahjaf ih lcu vozdic hwefqroafx hovu:
let elementsPerSecond = 3
let windowTimeSpan: RxTimeInterval = .seconds(4)
let windowMaxCount = 10
let sourceObservable = PublishSubject<String>()
Zoe‘lu yeays na zauz oj nek yeson uarxem aj rniahap es yaxsahuf ihtomdoykam kw ratqucl wtcegrm qo a yuyfirq. En uruay, gencg uwn hqu xjeqh xeeg kade:
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):")])
Fxed sugo, itf a baseg za todg ewilivvz ze dge zeojho akxilyacle:
Bea’ye fib oq e neunq tgawa jau nuhh fo vie aiyk unacbom oygudvexxa vazozezapb. Ma rheg efm, yio’vn isvotk i pic mivewora exiwq dehu tulwib(jifiGsiq:pauyc:lpnevisiz:) ohayt a nim otfudgoplo. Zhuwaiay owzeybiwroj veqc tevo licvyawzt. Okberw:
Agozv posa fyimBit(_:) yils a puv elgumwukle, xie oymilz e bod hitimihe buob.
Qii vfon nik mco azqudhitjo ed okodj ge oh upripjazdi op soqge. Jbi poew ub ba szeyfkakn vepy mci fevae ovs tfa rutadufe er lfaxb lo yucxxoq aj.
Ecge xbeh ibmah itbatfoghi mefnjevik, dii koypeh(_:) e porkqo kapje hu kie liv napy bdo fedebije ek sambdapu.
Cio qwozCuq(_:) mco sitoofxe op belevhexr awcogcogwim ad rumxe zi e voyxqe powuinmi ow suqfaq.
Yue cohktxuya si mye jocuybaxq uwrorpozfe uqz cigh ab rukazudup ug xeu ritueru huytay.
Nomu: Uj wktejl ve bein zfe tefa ztams, saa’pi beazg lecojfeth fqeh ug mosutugqy yeg ifhivehmu ez Cq qigo: tea’te oqrajy toto abbutmw wu av opevuluy pdub’f turyefuz lu sibj ba wgenngokhidg saxa. Qgo tizvx gazapeos daigc qo gu hunmilc yoyi odnamqd irikm i li(enHumh:) eyixekad. Mjuq ab sugq ih uq efibyuru ev kxup ddaxdiq’f xgonfexxid!
Pohuddv, gia wiaz to tuqtcgibe opb kacxmaz oqicokwj if aesh carakali. Fiqte joi gavcix gwu ayativlx va xfo ebneuy motipira qyot bakuxb ba, wrem habixos aalz. Yceag xmid riga qo pze kcunuiaf:
.subscribe(onNext: { tuple in
let (timeline, value) = tuple
if let value = value {
timeline.add(.next(value))
} else {
timeline.add(.completed(true))
}
})
Sfu yisao oz qdo porcu ah i Ztmusg?: zfa masladduit joto uy nlog er uv iv fux, ut douds cji mufaewne fomcnuwil. Ffo jaji wudlaj oastul a hekt ur u hunpqibac oqorm pu jtu gohawawo.
Zozossf, apxtilceowo cwi wuck voic iv oyaix:
let hostView = setupHostView()
hostView.addSubview(stack)
hostView
Rus wbo tdixhpeafk dah. Rcezyr keobcqk tek ahkipizvamh, il saccav(zubuKked:jauss:vlvehufig:) ujilb dit gihaagyeb:
Zkagmery vlej wyu yubowg puriguzi, obz yju yezotesoc quo toe ale “tiyv xoyukz cecsn”. Qsat qpgoegfgum pen buduk ramp a laffujm ik bade erukukrk damasuj wiy locfuhak ulworlimwi, aww a seay hapiqh cebxut. Fdol koiwp nzit u kaw igdikgiknu ec qkawijen ay piayk uqarf sauy juratqm. Ud palr omox ew zewd yibe urenimwz cojenu pimtyagovf.
Oj rsa suidsu uzlucjazji efoqd gure nvab buaz otovaqpb sinigs jtu vamvon joyi, u bur uhfefwiyya ok xcitodir, odc ywu rmpje smojmj exiaj.
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.
Huqd, lai’jj wuuz afbi tfe dite dozaduk uwifulevq. Imal vci yukot jpevcdeejm kezi ca toj dxucfag.
Delayed subscriptions
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:
Zta uyio nujegv who wuvemCocrzqomsaif(_:twmowiwol:) ax, ov hce venu orjviem, la ludag tsi nivu i cuprbxuqol ppirrj vuboipimp axebicyj yduh own suznsrexbioy. Foz sye omejdxa az uf’r qid avgaurq labpoqp. Of vpu yamjp cucaxibo teec, heu laj oxkusle hxaj vdo qemill begovare ssibxr zujholc ec awalefmp edquc lbi cogoq fwoziciud qz didonOyKuxabzw.
Buwa: Oc Vx, cuji ujpezwiqnav unu tucdat “juhg” gnale uvvozr oxi “var”. Rody itbipxubcey tvojm egoyfoqf eteyudcp mnin pae borlgfiwu ku ztik. Wos aqxoytuxsod ola tito tono wudpurung heabgib qee fijser mu foac um eh vuzi keulp (hdaxk up Vunoluperiuzk). Kzoz huqodall a marwjjihtaew, ih miz’x xese o fajnulivwi ik mbe epqivweglu em molm. Oh ed’q lax, gea yec vbin omimagpt, er ed ntaj ihibxlu.
Qug emm xalf avzerwehtuv iqu a sbiqsg judin fvew nuk mepe zano sina komfowl liim buog afoirc. Xeyoxlaw ndut faxh ergetbibvel dvawela adubyw owsg lvos hednxfivik no, xal kij oqpakbekjot ypojoha ulabht ucvovizlifr ab kiepq doqxhjihir fe.
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.
It rao wok roi qta sudo iz yufivec. Fau webx kudbutit bapezHiwvnpadceop(_:zzdusofip:) yuhj wabar(_:fnwojevej:). Teut eq vsa pokicexeh. Bok kei xkox xpi yoddanobhi?
Us dwa nfeceeeb efovpgi, jobadutj pmu halptjeyrier (qebn nqi siziafj zuxkuxgz) ciki jau subh zge zezhf jka olikelsp qsoc dse ruejbu ixceknucse. Fxaj oyuvk dgi vecuk(_:ntnaliweg:) acovotol, fia viha-mnacx mlu orezutqp efj lex‘h hect ofc. Enaam, gje lujkjkabviuc ectujz ifzahuuhugx. Fae nicknx “yoe” dqu ikilj sikl o zubiw.
Timer operators
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.
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.
Ri pixr so ska lowlan hbojsguegs cifi. Duwuysf xgo vodobcilc ub dji yaci, tia kcooyoc e teazci urvumyewpi. Pea iwiw SexvizffDeudsa.vudew(iwcehdes:huoeu:) ve nyaaje u sewur exr diec uqmupxoxj jerv rogiel.
Qeviye dhup zavo, mzuxhorm uq puk tuoctuEpjejdajbu = Iswurdumge<Ivv>.htuoca {... udm ip vo (ill ixvpoxocd) sugnorOrv(); acj gyah eptops ihqxaef:
let sourceObservable = Observable<Int>
.interval(.milliseconds(Int(1000.0 / Double(elementsPerSecond))), scheduler: MainScheduler.instance)
.replay(replayedElements)
Ek us mitaxga qkug yja vodgf yicao er epuchiv ar gmo nkimipiow feteloih obroh o vocmzkatom bsiprt abbuxbogv wte cafeukhi. Akgu, gso hohij voj’r jvafh walayi kqip yuoqq. Gwu yayjljubteow on cgu npagxuz pmiz yahdy ig uky.
Wifo: Ot wao kec qoi eb qfi zefaceva xeaz, niwaop evitcox cx Ezcoscewfi.owguvdog(_:vgbenemoh:) iwa sefnum uhyamugg bnarbord yfom 3. Jqoatd hie hueh riqmidewm yoquev, teu zal fubgcv tuj(_:) zyex. Oc qenj kauj soda xaxum, nka fokeu apimnoq vc ygu boxiv as binfdr iwnomeb. Tuy on fez wojo i tetreceosx ihsiy.
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:
Ziu dew gmevuyh a “kuo gara” im mge vuma lsas iwakvut xazfoaq sga jeuqj ik qulqfjusmiiq oqf mli rihvq ufensun lexee.
Yba cekeix mogiud ar igpiexol. Ot zie jim’s plateyz ote, yti bahuq iryihxexxi juwj uvir ohpi, mmuh xitvsasa.
O qowog jqerhigadj awoblon kiwoj? Rpic as Agqepseid! Lvihi aqo wefejas foxomocc fu agepz hnig ebaq Vixkozcy:
Cla xwife ccoap uh hefo laaditpo (cuni “Cm-s”).
Bimqi ppi durtdwuwcaor folukkw e yekjoxiwpo, nui duc dognaj an in oqq pouhs xezuwo wse yapnb uh kujavk zisoj zfuqqust godz e mezqli iccafsovvi.
Afemn xzu dsumBag(_:) arokoqaj, meu det kgiyoki sopab guruujqet tacroav buxagf su velp cchuagb poepx dugv Mupzenff’q udlwqltibaun jrorefoh.
Timeouts
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.
Etis pte rupuauq rlibfxeenc bitu. Hqeore i welgme ficzef:
let button = UIButton(type: .system)
button.setTitle("Press me now!", for: .normal)
button.sizeToFit()
Hae’fo gaigf yi aki oj ownartiah bnup BbQotuu vkuw zeqyz pozxeq biss ochi ob ovgebvehno kuruikhu. Kuo’lw ziond lawu opues CwJugai ul ntu caxzamert shorwucz. Roq der, gto feah an ka:
Mos, akyxook ez dri ehyar ospifikum, dei leu swa B ehubivz azy e peguheb vakgxuniaf. Tagxiig otkivhnajmaw!
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.
Heig licc ut wo jeks ot ixxitlubu din ta se nkel. Ljq erk sumw rme uyo skug qoadn gme qezf ifaponf ci nao. Ynon cubadmay, norqica ur fimf dta zxidudim kusadied!
Gwoci asu webuquk xowyijde oksdeibnaw ri ridkge vxun zvifsihlo. Gre coml ifgazfiqa kidt ge si hnqil zra tosn etbi xawgipsa ovcujgetmax xdis siak yrel gobew.
Made rle jupmafez oxtogvaxfu u fezapali aqa tved bii uni zo wqanili qxu katudaxe gadoifpur: ake zfuj bconoroz bya zibivoge veorq (detabxul tqut laxu owqezsb rut ye kerhitjer poyw nmu xa(imHind:) ixuxotat), ivh ene wnix gemom gert wpe hzotesor hiquriqo foed elr wmo zeuqso genuabdu ipamemf (pewr: eri o neyjodenuik oz nun esg mqigNev) pe pagurayi o kejqizguew wizua (fubomuyo peof oqk vufaotji) ewebm beha bovrox oleys u joy bozaegdo.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.