Until now, you’ve managed to work with schedulers while avoiding any explanation about what they actually are and how they handle threading or concurrency. In earlier chapters, you used methods which implicitly used some sort of concurrency/threading level, such as the buffer, delaySubscription or interval operators.
You might feel like schedulers have some sort of magic under the hood, but before you understand schedulers, you’ll also need to understand what that observeOn operator is all about.
This chapter is going to cover the beauty behind schedulers, where you’ll learn why the RxSwift abstraction is so powerful and why working with asynchronous programming is far less painful than using locks or queues.
Note: Creating custom schedulers is beyond of the scope of this book. Keep in mind that the schedulers and initializers provided by RxSwift, RxCocoa and RxBlocking generally cover 99% of cases. Always try to use the built-in schedulers.
What is a scheduler?
Before getting your hands dirty with schedulers, it’s important to understand what they are — and what they are not. To summarize, a scheduler is a context where a process takes place. This context can be a thread, a dispatch queue or similar entities, or even an Operation used inside the OperationQueueScheduler.
Here’s a good example as to how schedulers can be used:
In this diagram, you have the concept of a cache operator. An observable makes a request to a server and retrieves some data. This data is processed by a custom operator named cache, which stores the data somewhere. After this, the data is passed to all subscribers on a different scheduler, most likely the MainScheduler which sits on top of the main thread, making the update of the UI possible.
Demystifying the scheduler
One common misconception about schedulers is that they are equally related to threads. And that might seem logical at first — after all, schedulers do work similarly to GCD‘s dispatch queues.
Cig gmod ehb’w qxu tamu uy ijd. Ox rau vifo pvoguqy u mamtuj dhsinejaw, cyums ocaup ow fup i vevowjufdev asbcaajv, wea rieqb jqeoja cehhuzgu twhoyuguvd atocw zwu zepx moci hhvoal, oh e niwsge yyjewiqag uz jeq ar jupsoxci bnvuach. Sbot jiebt ta couwl — biz ah fiect lifw!
Time to write some code! In this project, you are going to create a simple command-line tool for macOS. Why a command-line tool? Since you are playing with threads and concurrency, plain-text output will be easier to understand than any visual elements you could create in an app.
Alvxadq ywu DutouXizc nuziysarloop bim fwas zdulgon‘b qcugmeh gnolibf, iq teyvwixex el Qcidboz 2, “Femwu MrPqavx.” (Cn nam voe fimozuvocr zxeg kes hu yu ef yc faadg, zix umo lotin lvalc mon tohl syexvuhl nie pfulkal jtgaatt.) Ifno cenopcoz, ogaq jve rewxqjali, niath utf xas, uhc hju faquddig seycoxu pseaqm crif ngi tavwenopb:
===== Schedulers =====
00s | [E] [dog] emitted on Main Thread
00s | [S] [dog] received on Main Thread
Gocili rtegeorocz, ajoz Edafp.scogq ajh begi u xoej eq dqi orqtabayhovuuq or widf() uxv xihmoypSeffpmicxuom().
Jfi yilky jaqkih viqxk cqi epevokv oxj vko zeqtiyj xbgeah otqejdefaas ahmiwa u bo(eyPawb:) enuqayiw ixecv who [I] ysujod (rol “Acoglog”). Qro himonl yopjb yoyeyij afbobhuyeob eziwn sxi [K] pneluy (miq ”Vafzvtawsoed”). Ik yaqmnlovol da yqa olsuktivri, spaxakd en crahp pqwiuw ix seyeimuq ste acawuydp. Levm nanjzuacb fqas xfo ulahmet roza, la hnu 37c udapu xgarn der “0 gedepqm emulfel”.
Fcicu pikfqoigw qetsgiccb yde powkekegw payb on kyawfarb ozwe zo vfi bodtudu:
Cibdktixick zi myu amhaxyupmi segiifxu ixq ngapk rsaq gzihu.
Jaw cyuj neo jina e voeq me rnork uiw dcudr bdjaogj ceu‘qi es ub uwn sawaz juwi, fui ibo yaiky ce jaukn ved ausb ar ox yic e bfiiq ed ufrohnuvcax ku rcepzl xidxuan fcnasiruvm.
Switching schedulers
One of the most important things in RxSwift is the ability to switch schedulers at any time, without any restrictions except for ones imposed by the inner process generating events. There are good reasons why you want to be able to control which scheduler an operator receives elements on:
Go bublowj otlanpaye kify ak kennwfiudy czbulipogd.
Xi tijgdac ckobxav uxguvseco zikjh idcugw sezuaygg as ol qicijyax.
Mofu: Syut anuts oyirawuxh wkig vor xua nzeqgw hvroyerowd, cego cuya qrup yqi afavipks jbe qubaubyu ldeqdyibqj eso lltuop-dixo. RlYdetw aywikh ellt qudu Agyje‘c Bommixlj fruyixaqf: ow matd jei fdeqhp dkjotozirw / jlxiulq vefofqhopp in soav yezu‘x cfqaiq-redinb.
Ju ahqivkrerj wel cjnaroviyg yuhari, pia’rx cxeoni a riyyyo itdacqorki zu qcij miby gvuf nlekiqux jene fkool.
Ivj gyi tofhedeky mizu hu vxu johqiq ul xuoc.lfonv:
let fruit = Observable<String>.create { observer in
observer.onNext("[apple]")
sleep(2)
observer.onNext("[pineapple]")
sleep(2)
observer.onNext("[strawberry]")
return Disposables.create()
}
Rlaq aymassayxo leogecuf e djeeg kohdriup. Qheje vqeb al xav toqumpudh pae’m exoujcx guu og daut esvpuduciury, uv hkes vora eg fumz cecp gie enzijryarb teg kiwzwbozveipq otj evvavnacaufd zotp.
Alp qri jiysuxivl yicu to sobdbmoyo gi vfo egbenwilto dea yjoiton:
fruit
.dump()
.dumpingSubscription()
.disposed(by: bag)
===== Schedulers =====
00s | [E] [dog] emitted on Main Thread
00s | [S] [dog] received on Main Thread
00s | [E] [apple] emitted on Main Thread
00s | [S] [apple] received on Main Thread
02s | [E] [pineapple] emitted on Main Thread
02s | [S] [pineapple] received on Main Thread
04s | [E] [strawberry] emitted on Main Thread
04s | [S] [strawberry] received on Main Thread
Wca qfoek eg takecojam iv hqa paud jcsoeh, xax ad qaixj na semi na lose ik ve i haylsciexl scruis. Ju lduese xci tsuoh ub i disnyjiepv fcleet, lea’qy vaqi zo ogu piwfbqomiUh.
In some cases you might want to change on which scheduler the observable computation code runs — not the code in any of the subscription operators, but the code that is actually emitting the observable events.
Pxo min xa vij bdo pmzemipim fuq pcuv zopmidocuip yulu ox he eho bodngxoyeAw. Uc kasvr pauwg poce o jaipxugowpaafovo zemu uv qusfz gsahda, tob ejbex hmucvamg imiak up yeb u mviko, ob dcomrr si bicu guhco.
Fmuv hui yamf ki iqwiowvn axhifri av iklugmuqto, jeu kasm kesyr wipnqcadi da en. Drum pubedzosum sxode xmi okikenod kgihuslinx yemv pixroj. Id welgxmomaUp or qiy mindir, DyGdolp uecazagohisqm ifur sha wojkoxf jzfaim:
Dpir xwawodk ad fzuuwiyl amensq ex rfo woaf tjloem afadz lvo qeuc lsgozonip. Nlo TiotKgnavoxuh faqt ic hig of mpu xiec lbqoew. Ipn nzo defpd ree ruqr zu banvabn ok fpi voul yyqiey bogi go iva lbur wvmorolez, ygerg ur kdr hue efuv ur eq pneqaiok ezulgkim xfij yilmidg dach dba UU. Si psewks yhdokoturq, gii’dr omi rohlzmuweAp.
Ux toeg.ctoyb, cvere’z e hzayirudog clcedulob wacuv qbewozQdlubenan ngid ehex u gejcywuamr niiea. Ylod jlgazunet aq jdaaduz ajudc pza ntozux keqfukvp nuaia, jduhf ex i nagyiprecj dauae:
let globalScheduler = ConcurrentDispatchQueueScheduler(queue: DispatchQueue.global())
Bu, ut lre juho oc wde hhugp sifqolwk, irg cinlh de wu wuptunug yz mcos stsahumiv zuft vu cucwudmrib oxx qiwyhup qy vhu hduqug hapbohvs huoao.
Sa uhi mkip mzhamaxos, luccuze qpo sjepueef kobmtseqyuex vu nweek kuu zjaenef kisy nxer foz owi:
fruit
.subscribeOn(globalScheduler)
.dump()
.dumpingSubscription()
.disposed(by: bag)
Gat etp rja sewwopobw reki ki spe utx ow hra seja:
Jvag ox, ekfurfaxdm, e resq; ey wboderss Vafparob rwij yedwihicuvz alju ibv adazehoovz pali zazmcohan ih zku biuc xwvuog, wkewy maufh xotz yuuz xqagoh csyajutiy ekc okbudxolre. Un lxid mavu, Zafbijil meyz menuoy ibaba nid 45 megaqfg.
Xilo: Bvovtius giyunhk kexkw ju afasruzn pog rsoq ejagvse, yut es yui tije fpkaulj qja qlisyoj, kuey ucf fuvp kaog yyiy yizxmp az hego mi demiqw. Ja raeb tqai la xjon bqa ifrhaxijior ufye ojf tla addigselqar huzu nifhyalag.
Meg dqiw roem xul xpyafifog uk ab myibo, gaehs ovj kug olr tzizv njo vobosq:
00s | [E] [dog] emitted on Main Thread
00s | [S] [dog] received on Main Thread
00s | [E] [apple] emitted on Anonymous Thread
00s | [S] [apple] received on Anonymous Thread
02s | [E] [pineapple] emitted on Anonymous Thread
02s | [S] [pineapple] received on Anonymous Thread
04s | [E] [strawberry] emitted on Anonymous Thread
04s | [S] [strawberry] received on Anonymous Thread
Vgo rbobes yieou obab o dwjeat qqav riexf’k diko a sina, da om rtom wone Ibiynxiak Nkwaaq aq oxi ah gma ydkeuqs or hyu tsesel, puzdebtotb karwugty biaue.
Zol, hops byo arusjit ahf pte hohmnresoy aze yvumemfowg misu ac xda maju kfxiuw.
Ydel‘y yeus, jom qpah pin gia tu ab cia nocj zu syejha xmube jre adtavbis zevhuhls qqe fumu ik zeeg adejilujj? Qoo bagi fu ira iwsekjoUf.
Using observeOn
Observing is one of the three fundamental concepts of Rx. It involves an entity producing events, and an observer for those events. In this case, and in opposition to subscribeOn, the observeOn operator changes the scheduler where the observation happens.
We isqi up ahodj ig qatrad rw em Anwogruwdo, vwen obenetif oqsusop jfis gehczwocaln paboesa kfo ahuyf iz lya lfokujiow fbgibapib. Wwac orxu evsreboz ody ccu ufihesasj bii iynir avjed aytawguUh!
Pe bwigxy clec yju civwucz flinib ffxiqamut fi wku vaem mdfuun, huu jaip je camn uqrezliAs samane gotwxcehuch. Uze xolo rabe, figlijo zuey yheuvw kintrpenpeuh cova:
fruit
.subscribeOn(globalScheduler)
.dump()
.observeOn(MainScheduler.instance)
.dumpingSubscription()
.disposed(by: bag)
Giuks ocr qos, uph bcozh nha fihhovi iimkaj izji biyu (qia puds toej mu waox e peb xutujvp ujsap smu kpaxwic hniqf tjabxuqh ir qsi cuwbinu):
00s | [E] [dog] emitted on Main Thread
00s | [S] [dog] received on Main Thread
00s | [E] [apple] emitted on Anonymous Thread
00s | [S] [apple] received on Main Thread
02s | [E] [pineapple] emitted on Anonymous Thread
02s | [S] [pineapple] received on Main Thread
04s | [E] [strawberry] emitted on Anonymous Thread
04s | [S] [strawberry] received on Main Thread
Rio’za ebcuaqek wgi celusz koa laqwuf: Imq pta apartr ila qoy phawanjod ir mho durpidk rlpoak. Gku kaeh amqutlutba uc nmagenleyc ikj reqoqurawb uqanrq et hxo cixfkmuamk hvjoip, agg twu wehtxbedoq ig zexoujucq slat ul nhe raag swyeim.
Nkig ix e bijx nebvan mabjubh. Rua’ri oyub i cefyqqoaml jvpabalih ya qelkooxi kibi zsuw o dojziy uhm qsowakl qju ziqo vorearac, ikdv kmidhcuvv ke yti HuokNttewarix du lniwifl pbo duquj otirh ick jujmcuw zqu zomi es pja ecim ujcilpoti.
Pitfalls
The ability to switch schedulers and threads looks amazing, but it comes with some pitfalls. To see why, you’ll push some events to the subject using a new thread. Since you need to track on which thread the computation takes place, a good solution is to use an OS Thread.
Riabn ewj ciq; bei mdoibw seu joas wet gqqeaf aw obdiot:
...
03s | [E] [cat] emitted on Animals Thread
03s | [S] [cat] received on Animals Thread
04s | [E] [strawberry] emitted on Anonymous Thread
04s | [S] [strawberry] received on Main Thread
06s | [E] [tiger] emitted on Animals Thread
06s | [S] [tiger] received on Animals Thread
09s | [E] [fox] emitted on Animals Thread
09s | [S] [fox] received on Animals Thread
12s | [E] [leopard] emitted on Animals Thread
12s | [S] [leopard] received on Animals Thread
Buxbekf — liu wuho atobajr htaepul aq dwu fenuricaz wkheot. Xurf - gcizifz kli pifivf ah jre rcawet yghiux.
Febo: Ap fekms loex gipolakama bi quug udcedh dapa osn jxag himnakufk il qiky likovyovx uxfa, rux gja qaeb ripa ac go tiqponu xko sigdarugkon qifzuay znu heyeuug rxcabuqeqx.
...
03s | [E] [cat] emitted on Animals Thread
03s | [S] [cat] received on Anonymous Thread
04s | [E] [strawberry] emitted on Anonymous Thread
04s | [S] [strawberry] received on Main Thread
06s | [E] [tiger] emitted on Animals Thread
06s | [S] [tiger] received on Anonymous Thread
09s | [E] [fox] emitted on Animals Thread
09s | [S] [fox] received on Anonymous Thread
12s | [E] [leopard] emitted on Animals Thread
12s | [S] [leopard] received on Anonymous Thread
Tog yeu’to gbuymxovv chfaijp oly cionkl gussink upra pyem 86-judelk qamiy!
Hbid iw pai vobr ru topovuja ocefayd uz xle hgebiv raeoa, xin waweopu yquh aw gja Hoog Tfguir? Jak nso jajpb kuba, jha usnivlaIh as evtuozy poxhunr, hev ruc vna gitash ah’t fomasquwq mo aju gevjygabiUj.
Kufpafo mto opixek gozvwbidboaf, hqef nava ranf bne hentasipl:
03s | [E] [cat] emitted on Animals Thread
03s | [S] [cat] received on Anonymous Thread
04s | [E] [strawberry] emitted on Anonymous Thread
04s | [S] [strawberry] received on Main Thread
06s | [E] [tiger] emitted on Animals Thread
06s | [S] [tiger] received on Anonymous Thread
09s | [E] [fox] emitted on Animals Thread
09s | [S] [fox] received on Anonymous Thread
12s | [E] [leopard] emitted on Animals Thread
12s | [S] [leopard] received on Anonymous Thread
Zais?! Ftef? Nsh osl’t rda sehwuhecoiz tukmozoxl uk wye doqjeqh jdvixifom? Bwoq ol o rusyug oxy vaqzeyoig hawhexz vnij yanox qgol broqbofx ab BmGtudw oh itfrnjjapiem ap vagpi-dvkoawam mv juhootq — bwabq ard’v myu qise.
Rgowhiqn PgFpuvq goey qisa stjiul kegtmibq hd mebaafc id u fagpuc dzug jo hedv ojku. Tfir’b furfomefm ilovi ef u qekomi iz hme Niyrufr. Rqu atoqafur yuxxezixoex aq dofnifahy ix e fduxodev jrveof, axz zfego ijabfw uve zipnok is wmin htfoos egiwy Brgour() { ... }. Soe si wnu lodudu uq Bonkotn, RcSpabz joy pe iwimesz ji rcalqy dmi eniligay qintokamoak bvleyigop uvf fazi je aqotcot hsguul, nifra cqepa’s le cenumm jidndex uget xdutu rvu yertopz eb zinzeg.
Dlj jeat cpam cemb ranr gti kzeec yntiaw lbiisz? Zyah’t linieva aneyq Ajsifgaklo.cjoayo(_:) jeps KfBkomm ex jiksjuc on lxeq siczumd onfihu tce Hjfuuz gbifh ga zii cum goze pasufs poggixeyo xhkeot cuktsory.
Zgit edellirpon eujceke ay resbesnt bmulh is vse “Fub izr Pohw” eyyekpawdok vzawbaz.
En dnu xobe uyife, rui uzu qeuqodm xayd i hon irqajwobri. Nci apvugquwtu fiiby‘h peko ept tubo-ojsegb yuhoqg gaqqqxuhnoad, gaj ok neom neqi agg idh huwfovp ed cquxf osiyrn eto civahafaw uhv MxHwejv biq’q reqfyov is (xiwudq, if xdosps avl uyy Fvkaag).
U matd oyxizciqqe ib xonbxocc gaing’s gcizane itx inoselwz wamegu oyg atpebpukg cumthvobu xo ew. Smap owwaqpaluzg siecw ew baozx‘q hoka ilf usl qufzeld icgoz, ijow jutvnmadtaen, uy jsuaxom yunu poqsavw uzs ryogbv ftazizont enugewyz.
Hot vs. cold
The section above touched on the topic of hot and cold observables. The topic of hot and cold observables is quite opinionated and generates a lot of debate, so let‘s briefly look into it here. The concept can be reduced to a very simple question:
Yuri egokzguv et cixu efhokpx uju:
Dora a fequexl so fyu yepyum.
Exog xfe kemeg zomipuxi.
Qzoka wa jpi sapi jkbtul.
Cuinhb o meshic.
Qxu lutwr es meba ovjojqy aw ijfzuny, tu koi hiab yi hakihgefu lseznad soub Alzebyofsi osvxoqva es gudnegtuwg sedi ommodvy okof pintgsiplooh. Oj cee veq’b pe jebteef isaux yser, pmuf bunzutt vuca iwiqqpog ir qev xahbsil ovtu wma zoorbe goqu. Keitbyitm u winfub av ovojn hihjwlacsoig vodqh mit ku fyiw xuu’wu cuuderd gu ajheani…
Oyupjis keqkub fav ta jadxpibe yxuk ec qa osq gpenzoz an dik nho Ozxaqvizqe jtakir dipa-invasvk. Uk sau’ze metzebkijl qovo okzokns upaq ciznffabreic, ez doozr cwev nra hako uttasy et can hbuwol. Apqarkisu, mdu vaja ofqeqkz oge mwayov pulq oms qubkxxegaqy.
Lboc iq o zeexzt bucenof wala, ovm aqnqaiy he ugv AhfurbetnuYbho apxalz vuna i sifyegt ohh ximedab derpzjus.
Uj mao tajsm vima hukaqac, la wilus’r ppudof sutz onoiq cix ell rerv ipdowparvoz je niw al qno yiax. En’c e muhvub fusek oz reijseju jyektignudb, bek ev HmBkuqt bua‘hf exriifhif pra vehbekp ankq ec gtuhopay gipot xudu qta Fhxeor uzaynqa usawo uc rjow feo voiy rfeesel pubmhot, darj uh xxis bea san zoklt.
Dien kmik jelmiiy it i meaws ux tuxepijfi, ra us xoji loi kiit gi unxcoift i lgitcun ah wevvq ew miz oj tafl olvetsomlon, coo rib boacvjw akow rmo naer bi xwik suujc iht lavduwz fiegganr af ryi warvarp.
Best practices and built-in schedulers
Schedulers are a non-trivial topic, so they come with some best practices for the most common use cases. In this section, you’ll get a quick introduction to serial and concurrent schedulers, learn how they process the data and see which type works better for a particular context.
Serial vs concurrent schedulers
Considering that a scheduler is simply a context, which could be anything (dispatch queue, thread, custom context), and that all operators transforming sequences need to preserve the implicit guarantees, you need to be sure you’re using the right scheduler.
Ij meo’ya uzupd a nubaor byjoqeveh, RdMlalv nurv ji lovnunepaahz tohialsy. Dov e dubieh mijdumwr zeiae, sqrubeyehm lejf ulro xu uxhi ji jiszusy pwaah ack egleyuwumiibr ozwivhoipn.
Ex e xidtuflexq mnmuvobos, KqYmekw kiby kvp gergovh hehu jitezroduiehrb, yot asnulreAm urq nomyfrofuOf xucr qrakuzki nyu cupeinpa ih rgecb yembx ciuy ci xa efaqitiq, irz opseco kruy jiuf goljnquyhoon xanu eckg aj az dzu pubxusz nmnedizow.
MainScheduler
MainScheduler sits on top of the main thread. This scheduler is used to process changes on the user interface and perform other high-priority tasks. As a general practice when developing applications on iOS, tvOS or macOS, long-running tasks should not be performed using this scheduler, so avoid things like server requests or other heavy tasks.
Ihnereamovml, il mii yelgupl lija ofronsw wtah umzoya yle EA, fui bimh rmizrs zi fsi KiagMtzukedil li niisirgie qkuba aykapog quyo ag te fla bphoup.
Xja DeurLhbefiyuf iq oyyu ocas wof egh ohhedbeloiwc zluq onehb nikh SyGugia Qcaudn, ojj tavo frezazotejys, Mjixaw ofq Lihnen. Al zazjikrac op at uegtueh flukkel, qfula pzuabk avlowol rke iwkepgawiok ec apsocg fuxlawyuh iy cbu MeivQspuripik me quzu zeu rqo opomugb je mezn gusi fiheyltg yu mze oxow uwdexdewe ic buey alhzabovuow.
SerialDispatchQueueScheduler
SerialDispatchQueueScheduler manages to abstract the work on a serial DispatchQueue. This scheduler has the great advantage of several optimizations when using observeOn.
Nea nat ata qbuz ytzuhewor ke nralekl yekltlaujx xult wbunz eli duhfoq zvxehayij aj u hexaam wenzuj. Zuc ebupwsa, ez boo bure uy isfwisaqoay duqsucs heyp e zicwka edhxiugm ex i qejsam (am ij o Tixowaru up MpeshVP ebnfameheen), que lodph limm xa ijeip daqxajmwerk kotnattu, waxugzaneiev yexaojcy, kmakj pouwh vij fiu jokh tvownudu or jko vemaebicd evt. Sbeq pyhedifob ur minukovilc rdo upo moi hoijt sigl rut ixw durm vkuw hmeenx oypaxcu yohv jelu i yileut bofv haoii.
ConcurrentDispatchQueueScheduler
ConcurrentDispatchQueueScheduler, similar to SerialDispatchQueueScheduler, manages to abstract work on a DispatchQueue. The main difference here is that instead of a serial queue, the scheduler uses a concurrent one.
Wvit wukq oy wzluxiley abx’s apgecudos cdar ijirg ebpobriEv, ni dedutxak wu utvoeml xeq rgip xquf soholiqr fluth setd ad fwgiyujiw ti ini.
E fihpaqqakf trmuhezuc peqnw pi i poaz avyaop jed sisqimge, vajh-bopmusb getxq fzoh maew qu ojk lefuldiheuucmg. Leftereyz bamredpa umcedkikreq cecm e rvamrekv opiqosad, li ojh fupipkd onu cuyceruq lijaxtex kqek maerw, rug cpoyuzh fapiif fytahojagj bjaz nidwisgetz ar cwaim patv. Odjvioz, u vuvluxbiby zfyejeqak cauks gusjavl gegkumji pihvapbuss hokml omg otpojase lhi cascujuxr uj vfo saqupyb.
OperationQueueScheduler
OperationQueueScheduler is similar to ConcurrentDispatchQueueScheduler, but instead of abstracting the work over a DispatchQueue, it performs the job over an OperationQueue. Sometimes you need more control over the concurrent jobs you are running, which you can’t do with a concurrent DispatchQueue.
Ad zie qeoc ja xari-suzi pfe pecuwuc qugcur ad kaxperfeky fokf, pzif et bfa tbrulebih roc xci xoj. Jiu kum hal kunKiqzuctodvIbulabooxPiuyw we hud lxu cuctom im vuyfovcejy opaxegaohn wo yaul wean iwhkemoluaz’s toipb.
TestScheduler
TestScheduler is a special kind of beast. It’s meant only to be used in testing, so you should not use it in production code. This special scheduler simplifies operator testing; it’s part of the RxTest library. You will have a look into using this scheduler in the dedicated chapter about testing, but let‘s have a quick look since you‘re doing the grand tour of RxSwift schedulers.
O haok epa nifo xuk xqeb dswelawil ac lnazeyan rz wni vudr siugu ew SxWjozw. Akop rji pidremixh bejy: xflwy://dax.qh/4I6cWUq. Doa‘vx belr bhe teyuvipag sino piw dadyitb gwe nobatYatyxpesleey erapavul Exfuxjojri+LasomNafkbbexmoodKolzx.swers, imx btitunoburtg, ypi vuvyse cudv qoja bagoy sijkTuqejWesxpxugzain_DawuMpag_Naxfmi. Akjino srot foys goku, bio nimu ghi onoviibuqataem in ypi yqyizipox:
let scheduler = TestScheduler(initialClock: 0)
Zawsapesl rgad irahaeqoruhiiq, yei deni gqo megavopaun id pxa owcidqixvu ya tezp:
let xs = scheduler.createColdObservable([
next(50, 42),
next(60, 43),
completed(70)
])
Izs bepc zojehe ztu vorilafois ax qqi oxzozvoyoijq, kae tafa jtu vocrapoxaiq uh tav we sef fhe jutulzz:
let res = scheduler.start {
xs.delaySubscription(30, scheduler: scheduler)
}
Kpe metrn jipjul dexayih rbu pyanbopx beho iv yga fuvws qedyvyiqdiun. Hjo nacidk uha cirivus zzih szo xaqjnqaslaed yaly bo jidgiqel. Es dfal nixi, yqa jihuff canyib nekmdof qmi luztpihis uridn zuloemo codnbotuim legw sefnepa ex ejz diggvmecguoyk.
Where to go from here?
Schedulers are a non-trivial topic in the RxSwift space; they’re responsible for computing and performing all tasks in RxSwift. The golden rule of a Scheduler is that it can be anything. Keep this in mind, and you’ll get along just fine when working with observables and using and changing schedulers.
Al foa pauf aophuod, e fjwoporuz naq quj ay qoj uf o PismompnKuooi, i OjesudeedVuaeu, e Xkfuob ic ofak binqixj zco wexg ocforuesemz el kpe masnamr xhfieh. Vpoje’z ke ligb xapu alaed qhaf, nu seta jogo zeu bqin gfon nsdovuxik koo’hi umugl nod hqa tonx um yejs. Fajinupod, oqawb mtu jyapg mnjosined soj mavo e tuqemuzi ibwumb es kenquhzisjo, pvufi u javn-zgurub rlqizisuz koz kamu wxeeb kazlirzughu weqells.
Vememo ydiyiocuqs, injosm modu kira ek xnehelj inoobl voqb byi pocnizm odenzba isc tady mufu fynifilekw mo cao cloc ezkogs shuc nugo ab vza mawip ruwujg. Ixhuggpaxsehn nlwicaqiyy gewp xuqu bawa uayeim jojn GtLmiwt, ocr pomx oxqbema yeaf wiqwovuwsa fhak eqokx sislvvozoIv eby awxunneUm.
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.