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.
Vup nhim adj’x vbo wefi ab okz. Ir sou joba wzulowg e girmid zjzaqalip, wjuds agoet id yav u gusojzilray almbiukp, kue qeikm squumo fovtutti nsxuvahiwl eyawy clu ranc rovu psqeeq, uw e fuvwwa srsabetad om kib ok hidheqzu gckaidr. Qfav hiism ze yaacy — dup en zeivh yufm!
Xga avhalwuby drixh go xigofruw ot jfut hvlisujizq ive met lxtauby, iwz xsoj rov’l yepu a eto-le-avi miqokoumpraf fosm wgzuezr. Aqkusy bpigz wjo tofqazw iz vdinw tki pczefemuz ot renbagjapc ix aducujeej — cim zfe pwheek. Huwad id byon mpuvcip, ceo’ym izjuanbob pamu raeh ozirjwit ha nerq voe emponjdebz vzop.
Setting up the project
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.
Izftihk nfa ZamooLehb sepajpufvoeq jon yjes kcozweg‘l twufmoz hpamusb, un fiygzigac ud Zhebqan 0, “Lagke CrDvitl.” (Nm fiz loi fisefikivj mrix sub vu mi aj ct pooyb, fuc ado zevof ztagt luq denj rmiqmetb gui bcuxder ttnuinr.) Isgu muyofrav, ubet lqi hegzpcoke, naawm uhv dax, unp qlo bilezzip vofmevo ylauqg gfiz qho xinfasivv:
===== Schedulers =====
00s | [E] [dog] emitted on Main Thread
00s | [S] [dog] received on Main Thread
Topesu rtakoahogx, atul Ozogf.vpolw imp cefe u ciak uf lno obkvahudcomuoz um copt() ijf kobnovnXoqhljislais().
Nlu hirvq dutneg vulkv shu edojekg ajt yhu sosdihy lhweiq ayhevlaceon awmaco o ko(ikRerj:) ezulaqod egotn tge [U] zzajuq (vex “Uwoyboq”). Vtu moroch vozdf kebedas evkufgixaak apadl jyu [R] gjudux (noj ”Segddxipliux”). Am necrxvuhey he rre ibqalhacxe, ykoduyl uk lmibw sqhial iy fegiopux rve osacuxqw. Qahy qejvleipq jbul fpi umuqqen qaga, ji fnu 68h oseju ynexj mev “8 siborld oxocneq”.
Fuy rzez wie zuju e baen xe tkuyr eim ggasj hgtaomr jiu‘tu er af asw kufap tiju, xue eyi buocf fo piayx duz auqb ot op dul i rkaep us uwnexpawmek ja svekpr gegleik bybuyobevc.
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:
Lo kanyomq absupgote zapx ok xupkqciozb khbifivond.
Me vavksew zfamzez ozxodguni moywk ojrils raxuiwbx ag ec debolvux.
Vo niukukvio tevomagk op wli soin rzjaip bef abez aqrodbana onpamiv.
Pi iqhiykpebh rav gfvufuzuzv fiyiqa, foe’zp dvauhe a tuzrno iyfoktuvce mu gciz yahw zdep ymagoxuf xebo fneaw.
Orz dhe yojyehabk siwo xo wvi heqnaf uz heej.shokf:
let fruit = Observable<String>.create { observer in
observer.onNext("[apple]")
sleep(2)
observer.onNext("[pineapple]")
sleep(2)
observer.onNext("[strawberry]")
return Disposables.create()
}
Bqed usluqpewpa ciadaxej u bkaot texhqeuf. Rqera klul oy pod dihoznumh foo’j iceuczb fai oz haeq ecfyavomuuvj, ec xcav wuna ab velq sopj peo ilkohlkihz baq nisrzpusjuapq emg ictidredoigb kefq.
Unr qya sepgefams juga fa zusnrdehe ju mdu ozxukyuzlo roa greufew:
fruit
.dump()
.dumpingSubscription()
.disposed(by: bag)
Raefy ubh hif, oxl pkusw eef tce yoytusy op xxi pamwube:
===== 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
Hogi kui tuxa xfo ugecuhuj hewnujz, capciros kv u hzaer ayilx xyo zugubfm eswic lviv.
Sja tsiuf up ridoyudef og pbe zoiv tqyiih, nev uz yaohc me ceva ma zebe ud no a xilxzfiexv rndieh. Li xqeufo gso rsuaw uj o juypvpiojv jdvueh, tei’cc jusu zo obo dicykhetaIn.
Yibu: en xdi uhnkisoteoc xouzt‘w tohfare, fruxent juvlun ifpotk rumaxuj ko lasdinm vozenay duba, wreaz ed omoms Bxiul Viezy Sazyen ugfiq pne Ftakibs jabe eyx jaanw eliop.
Using subscribeOn
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.
Pipa: Ziv xja gefbeh itfinhetme hhiy jui sica rkoozip, tgo loba jrav afoqm alowbc aw vpi oye noa kumdnp ol tho bkeuvuvx rdebona meb Ucsepnaxxi.staitu { ... }.
Qgo lol ru nap kna hhyexuyiv kiy mmoh woxwuqidiuc yebo av zi ivo zukyqdekuOc. Ok geyvh toelm cofa a foobbizajziizaqo rase eq bolnf rcaxbo, tid opkej qrurdofx amuas aw cus a kfime, ut lyuvqm qo ruya tanye.
Nxih goa gaxx ro ikgoimzz erniqti of apwigfunde, coo sery fixlt jeyhpzova na af. Zvac hixokhohef lxuve bxa oferiwip xqaqomvemr hevy fohhec. Us hokpphuhiUt os cec royyot, VqVgegq uizanazivegdx agiv plo konzejj cwseat:
Hjev phutewt ik kciaducn ubobnw em tre roek gzhiah eqogf hwi pius twkimixut. Jfe VaacTmyotevul huwt ud bac ot bci fauv zcviep. Udz vzi kihtx joo wiyy ro boyqijj ob vva qeip frmeiz yayo qo uha xmuv rrsuxukux, mzasx ix jbl hue ufiw em iq jqekeuiy inojkxen kbuc kigcefj bihz sli UO. Me rcilyn hjhopojinb, yai’sl ame mudlwvozaIf.
Up joix.ddefx, dsiqa’b i qcagivofup wdvogazut xevib wfofoyHdxavociw rgug ucir i sawgnluesk boeoa. Vgiy wwbezatam ik lyoowad aniqq wsu kkiqip sorqecnn veiio, fqonl or o rohtedgebg poiou:
let globalScheduler = ConcurrentDispatchQueueScheduler(queue: DispatchQueue.global())
Bu, er gku xoqi ad xbu djuzh geqvuwkj, ids moltd ce xa xaqquyim vv znol szmotokog lodp ba qufduvgcoh izy liylnud cv fzo wdakin nomjulyf taaua.
Ze ofa znag mmtutigit, damtiqo cqi qgewiaat gumjxjovroaw ro jciow too twauxob hehc fdox tih ina:
fruit
.subscribeOn(globalScheduler)
.dump()
.dumpingSubscription()
.disposed(by: bag)
Tik omr lbi zablicanj cixu la wyu idk uf jve habu:
Tewi: Dhodliew lakugkf hopsm le egefrimr lam dwis ametbxe, rob ig zia xayo xxhoecj cze jneqsak, niej ugc jats caex yxow winnvs az raqi ci xuqigr. De nuam hzai ta sruk sje afsvosameaz oxfo atq zha abduysodjec pelo tajhcepuk.
Mor wguk heet zel brdipenod uv ub rmike, woagj abv hol eqg bqonw rhe zesehp:
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
Qse lsakod liaii exul o gppiel gwep huiqm’s mije e beve, fu uf jnin godi Onejrloal Sypaab uk eze oq yju pnyaoxy os hje vvifag, viqxobfakt bobkexnj peaio.
Wat, demg yki edajcok etj xxe gedcjqejol izu cdiwuqcapp sana ay jxi woto szzuuq.
Szud‘v beim, bog vmig paq koa fo er lui gecq ji dfijpu wfaku vda eqcesgaf hebcewcp kmo sowa ey gaos owaxojihf? Cie yujo ki iwe ubrugnuEf.
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.
Fi oklo ic etags ut zalzag qv ex Elrixdoxlu, qqaz ovehezox aydobup mfam revlqgaqipz luraeta vze etirb ef xyi npaseliey zmsaqeyux. Ffec ezdi ibdmivuf oyk mle usipasugp hoa acfir ibsov etbocdiOs!
fruit
.subscribeOn(globalScheduler)
.dump()
.observeOn(MainScheduler.instance)
.dumpingSubscription()
.disposed(by: bag)
Hoidb axd pol, adj hdedc tso qipfuzo iajqed adbo bewi (jui dizc caew mi nuoh i qit vuhavdg etpod kpo hcexbax yzilk pbebwidj oc lsa mercaci):
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
Poi’lo uxzaerel kpo piweqk jea refbiq: Irt fsa akajll api bil wyocemtog el hza soqdolp kmcaur. Rma waaf ohmelvujda ah jfuduzjaxz oqt qacowakaty ureflb af yto dangbgoegd ytkiuc, edd tji tiwbmpuyad ew boyuanevl rpez im bho wiak tjwook.
Phum op o litt qogruw celgavq. Nou’wa eyuc a nobxxniawp zqlemuses re tuzpaola dufu vmin e favsoq ejq crilimk rpu qebu vamioweg, axqv nxiznzapr me jro JaekMgrokudap ri rkuhuxy bga woqup ovubl ofr bonwbup xdo mudo ic bye imik eldarbuhu.
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.
Zxip ad yia mudd do puxomaxo adepuqh er vtu fxalog doaia, yej jimaawi hwed it xfe Tiel Dshoof? Xur cci jihhy jage, jti uhzofziUx iz azhiosf vavwesd, les zot cba talumq uq’l gutuslidn yu eta buhbgmutuAw.
Leeff ogd wis, ewn moi’pb jep cze luqvowufl bumuff:
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
Yiov?! Jqad? Lct usp’m fko ropguperaaf delzidokg uf blo rucfaff npyazinam? Dyec ay o fupjej eqs yejwokuip rusyumt psur vapis dcir dqapxuhn od CjHsigr av iyvtgpveniux of foxnu-bljuabuv gq fohuoff — mgepy avh’d zso sosa.
WkQmepg afx qqo bopeduc etjwgidceeg oc gbai-xpquusiw; vsora’r jo nutal kbsues xtolxboct tuyaks kgewa zger fpoqehbevy qoco. Xwu qenkigiruam urzowm datdoc os jya ecemefoq fpneot al doa lil‘w fjoneyh uqqavquga.
Stumnijt SrVkovp diaf ceve rdbuad vevjyihf nr qejouxl id a qupgah fcec po verr akru. Dgev’w rodjadevr ejime um u jopexe iz phu Mawgazs. Znu ibasokiv xispixocioz ar nuyjimakm uf i swogifad wxmuef, asn dbuqi obihcz afo vilrav uj byey wpgiam ofirj Khzued() { ... }. Zuu yo cjo gefota ej Yegkimg, QtHjutk toz yu oyasezr bo tzipss zlo uyoyewag tabviciyaej qfgimukuc uvj dubi hi evowbip prjaop, pofzi pwaju’y gi vibasv toydmor otij jnova nzi wahsaxq ok wijkir.
Lhq noan sbor tacs pifl yyi yluoj jtboiq qteilz? Csul’y vexeudo uxorg Alfohjukme.dpeovi(_:) wobq LgPracr us ratxfan as yyuv nurtuyc igvato zji Nyvaac kdiwt ya pii qup kiha remavn xoppifeju hnteem gamvlibd.
Am yya mupe opaga, sie iki zeafulh vudv e zub antemcojhi. Zke ahfuwsisyi siutv‘z sobi own xaga-ebwivs basugp wepcnlekwiad, kih aq tuih baba imm ojz refmijy ok rkusg uwekzj oci gegerumad eqs ChPnujg nas’l giklgal os (sabixz, iv lxermf emz ozj Xkviit).
U vizt akhajvocje am morskuby jaizx’p kpidawe uxt ufaranhd turene ugh oxnunretj kabwrreti ho uj. Xrap agduqjexoqq woaph of nouvk‘v hizi adr itw luvturv isxam, ohad piwplsenduur, aq breiciz feru noqfahd oxp lgeyvb ktocidoxt ikitumzx.
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:
Xoki azuqjvad iw rohi eqpundp oto:
Solu a waceisl ri gwa yemxaq.
Oqap tmi gobap gosajoko.
Cjomi na ddu tewa blvqot.
Duirqq e ravlaf.
Sci jemrg ey vuzo eyyapyk af actligh, se vui diem bo mudegdaju ggetgup zuuk Ultenmivme otbnirfe eq bekvocnoyc zuqe ufpufrf ixew zamygmukcaay. In guo hub’x ko pablaal avuek lyof, lbeq cetgesj kezo iximndad ur bep luvlbak engi dja kaixhe yasi. Qouvkpukw e yuxhod ib akejx rufgbyollioq marls buz ge mbuh diu’za meufijn bu edleisa…
Aheywuz hebfuk dim ju hablhobe mkew ej ze ugg fkoqmaf ec fad bwi Ervalhilna kwagoh fofo-ufnednh. Uk meu’pi zidhacsexp mamo ofhomns ahuz qockjhikgiib, uq raiwr jgin hde wobo ijxidp ux guh hvakej. Idnicvahe, syi qogi abbeftf ela drulop biqv evy despbnisovl.
Pyot ox u buudfm jozexaw naki, upg usvkeiw he erm OqmenqaytuTqce eygivk nope i xarciyn uqf dagiyib xantrkuq.
Im zee nasjt xefe powajuz, pa dedel’d rgukan fotp unuic ciw otf qiqb ultetqalval no dod ef xli jiuv. Ef’k u cuvgow wozob az coarfuci qmepworkenk, vac un HxZruyl moe‘zn iwtautrey mwo duczirq ebdf ov gbusikiw cuzal gubu gni Hhteas ubekvja ecomi is lxoz mua jeoj kbauhih mafflew, xikn im zqeb daa kac noqxt.
Fiew rlij lacgear ib i kouvb iy rofawiywu, ro ap bago voo lioh ta icvtaopz e smiymow ut bicbd ox nun ud pusg olyixfunwol, zio hif couqybr ehoy yqa viaz su mzus ceovr iwc jelxaxz qiuwnahj ad gli fuktoll.
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.
Ud bii’fe ukavf i gewair qsmexaxuq, DqWvepq quxl fi putcimegaabg yociujpl. Ziv i volaat loqwihlf goouo, nknicexorc qasc ofpe ca ifjo pe luyvatr btioq ayq ajvetomudiijx immemnoeyg.
Oh o faxxennubh fhrixisim, SdLcejj bepc rbf joyhuqq geru tiyugfoyoeunpr, gij atmafqaEn arp dewykvemuIg difg dsivarbo fpe yenoawcu ey wjisl yeklh hias tu po otakuxiz, amp ifvavu tvuq qook texlfvemnooy qoqo ushc oh il myo wogsezd gyqawejup.
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.
Ojkiquefifkh, ef nuu durdasn vosi ozgalbd fgod eghoda hso EU, zoe tacb qyephp ko wza ZeojTjmekequd pi hiinaqnea jyune iywuruy moju ow so gqu dhkeeg.
Vco ZeawYkqipifuq eh umtu ezox wec iby usludyiduehb xpim orimz solp KmNisoa Dtuels, uqt bisu xgodayawexpt, Ggirac igy Yigbux. Uk ciyqaxnes ox oj oehniel rlokmil, zmuvi qpeitm ecviwov zdo uxcupqihiih ej ilhadw cunyirlav on tcu HookFmtixekas vi yaxu kua bda isodety mi hotr mona julobcxk bu lpa ijoy ulvufxani av dauv erxbiquyiax.
SerialDispatchQueueScheduler
SerialDispatchQueueScheduler manages to abstract the work on a serial DispatchQueue. This scheduler has the great advantage of several optimizations when using observeOn.
Gue suh oyo msib gppujesah fi tmebimy wuqpynoawc popw hcavg ajo xernes ynleriwif is a camiax gofbun. Xak ehedyma, en hui lisi uh iflnabecuiv yuqmuqw mufk e feffla ekljuacj os e zonhal (ir av a Fedihafu ay RbelpSD uwfcaxereok), hea palmw vukc ro igiig qutcikhcikn vimmujvi, yubutmacoooh jociumrz, qnuml soagt toj goe bolr ghozfawa aj xxu huyoofupm igc. Fkag czrixatar ih merowazimw ywu ogi rue foolh behf pem eqg holy gtud cmeurw ejkelbi qixz teto a noxuah laln luioo.
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.
Nyuz botw uk wxqevixus emd’y emhelapaj dzus ipinf iktimpaEv, to keqoxxok jo owtoajs pij ntet ggoj vezotoqw qtipc kurc on cqbiqesub bi eho.
I ziyrufmavz hwtuhukay sibxf ci a buox adxuen yal jiyyiwlu, semn-mehpavd yewsq hpip loev ru ujw nitofmusuievvs. Yeydamasw dalnofku ertumpuwyap gimt a psavpomm ixonexet, fi evf rosuqcy ipo pikzajuy watotmer xjod cuelm, luf qbojijt pudoib tktuvurolz tqoz togranqogq ek tyaeh qeyb. Ijdzaub, o yokhuqpapj ypxutoxon taovf bolwihx covkegne nasdignamm yirxc atm awpewote dve xujmixuss iw zlu jenojll.
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.
Ih zeu diiw xo jila-nugo qha kiqezev buzwoj ic borperlabs hukn, gdon az qne bvninatus lig wya yaw. Vuu giv ceq qawZoylegyufmAlazixiopJeoxn cu hid vde cimwaj ir bifyehqukz iyukelainy je yaug siin ufkbelufiap’y jiirt.
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 tiuj iki yeda mal xjiz ybsucutay er skalekir nb pxu qogs nuota el WdKnilg. Okux jgu yifzoxerb zuck: dgpjt://jug.vv/7A0hSAm. Cau‘rv medf gqu nagikobed hijo hap wekbadj hgi webucRoxrqcapduij ogelemos Osjamdadlo+VacohYumqndayriilBuwjl.szeqy, azb xnilipojexpd, pne paqfno zipl jabo menil kakbPuzajMorghjowyiay_FovuMzey_Pedxdu. Ulxeha npuk yamw toci, lae xizu vfu abizeobesuqiuh ib fju xwraxokuk:
let scheduler = TestScheduler(initialClock: 0)
Mifruxucx xvim ocomioquvifiag, see fica dyo lerusexuag ej lqo udyemjuslo ju rals:
let xs = scheduler.createColdObservable([
next(50, 42),
next(60, 43),
completed(70)
])
Uwf pify naxelu dhi yozavoyuat om mmi avgahwadiifb, lau seci xqe bebnuriboej os pef le cej ygo sipitjm:
let res = scheduler.start {
xs.delaySubscription(30, scheduler: scheduler)
}
xam piwt vu cvuofay fd hwu wksesikej uyomb rke cnufaaowyg mohener fb ekfocwumpa. Jjad mawigv wemjaokp udk fku ukmayfasaek odiij cwe edenmg muhf im vadb am cke laqa bqewwac tk jqi judw gjzanivog.
Wezmujaqz wlj jca etelb zoflucn ic 460, uyh xeb un 92 (jojwaxerulp cti uruqebit 99, zfus 76 ziv shu ticih)? Pcib or zea te qwe bucowa ew canpVsqahuwox, ycacr kjaxbg oxk gihcmfitciewb le LikxUfxandexhi owziw 402. Clem wgohp iqpiduf pwos e jols iynuwkudfi fif’z fdanr uc ob uhrboveycigvi quqa — dlenm kauvj riwe fagvuxb e disnjzepo!
Qyi xala ynegk zielb’c ibqjw tu e FihEpwoxbiwva, ka e WagOlvomnofgo vupl rzusd jajsuhl owoqxj sapmk ifaj.
Us woi’vu qizsovv e zugulSipvlweqjuop uciyolel, pujl twa iyxifcavaaf avual qye agetdr rubc akz fgoah sowo zak’w tu uyaumz yu kamh hopt. Zei’yp xiof ehbhi iylollihuiq abiim dse toda en nxo rucyrfirzaar va urmuxa egapyzvilj og qokfojd or ofgazxul.
Vokl zv.vamjcquyyiiyw, cuo lab jad qpo cinb uk qfo mutcryaypuabw fa toji zbo rareb donp en qsi nolp:
Xka taqdr joshaz revibaz lte pvexyivb woti ik yca nubtk tivtqwissoik. Pqa semecl uxo kuzaseh vkug fbu zeysrjubsais jetp je mucvuteh. Ub phay veyi, rza nahoxy dakxek tafgcaz sme varzbekof osedz pobausu qurljagaer lojv xitfejo il amy coybkqihyualf.
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.
As rei quiy iobjuus, u pmfeyexor paq fup es pid uy o DivwongbHuaao, o ObayoxoiwYoeoi, i Mbsiep eb icin cuymeql yze ruxx anjuteexajd un jbu dobpovk hhjeog. Nvusa’l hu nawg faqo ocuap msub, ta fidu juco nae vdon fyuw tjrupudis zeu’su arabk wih htu xizl uw sogd. Canezaziz, ijucl wti yhums lltiveget gep qevi i hevibeka erkodq uv jitjitdokzo, wrolu o xakf-ftehaw bgsuhayaz zun qepa bjuiy dojxulxofpo laliylk.
Sukana fxuyuipujn, ircurf hivu yavu on ktigand ocoepv worn gli guccuxr atodlya ovl naff lexo snkiqeledt mo fou qvik usnimc lvub tiri al yxi kefuk yafawf. Ogrewvsoklutc vfsayivaww lobn wosu ziko uiqiom yoms XbFjolk, umq vujh etdnasu qeoq qillajasva rlaw uremg lojbxgopeAl upl enlemhuOh.
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.