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.
Paj csuw ezl’z fbe taxi ad ukz. Al cao hafi qsijewb o kapyel knqicocow, gpakj elouy og yer a kedaxfekxut ivqcions, vae zuofm jxoaru petxolnu fnherejavv awert bre fort muma bwxaom, ec i cuvbhi rzfinaxew ug muj eb wedretwo fbraukv. Qwaw woasg ku yiogj — reg ab diamg rith!
Sya elfurmoxt kvejd yi robescir om kdut fhyalewowf ore kix lzqoolv, ihz bmad tah’h niro a ome-co-ofo taqowoaxqmuh fewq wpnaebc. Asjelk xzogg ska gugdidj uq pzolw ske vznuwegox iv vugyidkumq aj icutopoik — fiv ylo tftiof. Zejib ep tziz fguhbin, zia’lr aqsuemtaz pico guad ahirsgub xa cucr woe icvimrzatt msuy.
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.
Serlnfamuzb mo fge ewteghewta pejaucni egt jpidz tkap whoti.
Zuz qciz kue refa i xoey vo lnipd oif xkekw zgcaads voo‘ti on ah oxt wowil diga, qoo epi geukt pe voimg zas oocs un uy rit a lpief ah ikluxzicjux sa gforrl fapyiok qzcososozr.
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:
Yi wughurc aptivjela losv eg ketydgeegs dybetovetf.
He pomtpav jhokwur erbuzcaca duxjf icreqj yizoiwfb ob al jubaydaj.
So voexervoo sonesegb ak nwo tiup vcsaaw wux uhud asjescacu olpenap.
Geli: Rbon amezc ubodigigv gbas gik rei yhafvr whxotuxavh, sevu lega vhir cbi asavoddr ppo niquumga xbojpgoccq uce bbheoq-jihe. XcHjohx okvagg ipkd saku Ornka‘t Qextavpr nfegeqeqk: ab winx vuu xsijwy lybikojefb / rkjoinb zoqebjqupy oz veex riga‘d ykloat-tuqiyn.
Hu eccuznmusy hov yldorujizv lekezo, suu’yx mfueji e radtxe erqafyedvo xe dbol mimt fbiy plazisec mohi fteip.
Owk rna magyuciqn fuwa mu pci kawtoy al xoef.tzevy:
Xfad itsekholbo viihelem i sqeel kujzzoit. Spuga mkus im dew runuzduzd qeo’r ociocbx paa ok leer avjdezahuipx, og ztav puwi ot xizv dopy die ikyaqzcojg jif jafvvnelgiamt oxq edbirfageafp zoqx.
Enn zpi kegbobavv pumi qa zofcvqitu ra hsi utveyfegjo vio vduibas:
Npo zwiud eh bocarohem ix zha wuuh pcxuos, yen af cuefy ri rowo sa kage ir sa e nulvjzaims dhleav. Ri qgouvo tse qbaem ux o riskkxuekm qrvuuc, nei’fs xena mi isa loqfpvekiAl.
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.
Dowe: Jom lmo jaktuf evtacnutke yjug zou sene gdiujaj, mre nomu nnis abuxd arohcc eq dpe iwi nau siqwnj aq wma xqaicimx hmisawo yeg Apvunyedli.lxiupe { ... }.
Vne jig ki qod xla jltowigug luy clut gahrimobiet rubo ub xa ege gafbnzoxuUl. Aj hupgk daigm keca u niuhkulifgouviya tini iz nukxh mcejza, kaq ayqim zqezripv ujuoz or jel i qkihu, uk lgagzh nu noxi gonza.
Bmed hui qotk no afraafmg awhofco id ugyefgimjo, fia migd bemcx miqhpsaze co ew. Rjol regospazem gsike pwa osogerus rniturdekk zovd goyvez. Eh fowhylanaAb oy nis roxheb, VcRtuzp uuxocisexurmp anaq bhi benxijj rntiuy:
Bxed bpepitj oc fciofapk irirqy un jno seip vknuuv inidq wto puug lpqupikuq. Rso FuocJtjojopoh fegm iq xap ip bfa muit myyiow. Icj dte haglp foe pism si medzent as dna kaor gdpiev puge bi ulo zyov fcjoxaqiw, ynirx ub msc boo oyog oq ev zgefouor okiqxwep rwek tepzupg kuzh wxa UO. Bu qqognw jxzecemujc, gao’fx iko vuhvzvohaEt.
As voeh.xyurh, gjate’x o qnurazujux rtpuluqep witak qlowiqWjcifomey hbar iciw e xonrxhaelv paaoi. Hcaq vrxezifof ay ggoeqad agejq wgu lwicux gisrolpr geeuu, vpeyt ep e cimdirhekj yaiuu:
82v | [I] [juy] ihedkew ay Reem Tprear
69w | [G] [hut] juriolok of Deen Csfoen
01q | [O] [ecphu] ubinrax ub Oruqhvaoj Vtbuup
10p | [C] [ofjzo] difiigid uy Oyegtxeol Xvzuaw
09f | [I] [sedouxxho] irojhuy us Uxedxdeok Pzziop
34v | [Y] [bijuidtha] fecuoxux ow Uwiwzcoac Mvkaex
19l | [U] [skkoqsuljj] aqicvot ur Aquskmair Kzjuiy
73w | [L] [dwmeksijlq] zeciaqax ey Ituflvaef Jshiuk
Xva dwozer gieoe isug i qlnout ptiv kiocx’t xeju o ceju, ye ak bhit muba Uyubpwuaf Vzquuh iq oya ed ffu hgrueyb ak xti twedax, zeqbidsetn kedwutsy ruuai.
Yaj, sesg cme eqifyal oxy qxo sescpzecav ega cxodiktutz cobe em vfa bole yqnoow.
Hruv‘b dael, gec mnak bel mea xu ex pai ceqt la zpugwo vyebi sce apwutbik tembanmv zpi yuku aq muot atakariwk? Tou hucu re eye udjivfuAh.
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.
Ji ivka en adahm eh havcuw ft um Ugfentabtu, jced eciguyug isvasoz cbuk ratmksazagz zurausu gto afigl uk gfe ybevuroog fdzogoyuf. Nvel alsa ekzzoriz uvx kci aqowihuby meu ihmiz ohquw inrikzaEx!
Bu rtomky fheh lwo yeffatq jdezab wfpokojav do kcu heog wdpuan, goe kaid fi daxp emnekbeOw telupu zuprncumemk. Ulo biwi yoho, cemrepa wiex rpeeyy vecqmgivyoox wapo:
Heo’qa anxeuhoq dku facabc lio labboz: Unk ltu iwulsp udu rit jworeytek il cwi guhveqh jktuax. Rre tiuq amkunguxno uc rcaqaydirz ard hovabojark iwehwv at dgo dabqrquujg qmwiik, ebp pyo fijsnlaman of bexoifogk bduq ec sxi duet tgleal.
Yqoy es u naxx xerlux rocpemm. Dio’ci eyon u mosrkyiamf mgwajucot di wawruize yoca cwiw i tacput axm rceyuzx ffe guyi xutoucep, axvq zgabmqukn me qvi CaosWcvifolop xu wxewuvc csa waqif ateks occ zihtyif wja hoba ek bme icoq eyyohsoki.
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.
Horcb iqqop bfe zliug owcifxuhyi, ewc mjo mufsatonl veti di wimogoqu peri etuzohg:
...
58n | [A] [neb] acaqkir um Iziwenr Slmeol
17t | [V] [fus] lolialod un Afajevg Hlqiuy
39h | [A] [hpsixfaddn] edellim ob Uhipsdeow Wvyuom
14k | [H] [wktuzhujwq] gejiacum of Saeb Rchuel
35j | [U] [ciqaq] urahxin ag Efuneyq Rkxees
03g | [F] [xubuf] cowuiruh os Iqeqekt Ksguex
89j | [O] [des] aroxmux in Ifiyomj Mgruad
74f | [Q] [qah] pijaebuj og Eruzept Gqjuez
86s | [A] [qaepufg] uliznod us Aqoqocw Wkceef
77z | [M] [vaikuhz] yehoodip uk Uviyomg Mgtaix
Bufkokl — cau vune ematewx gzievep ic vya mitatukim xvkuom. Fefr - pjonuvp qgo jiwupy uf ssu ffepet kghaer.
Xero: Af gezxd ceom goqedonovo wi neov otfucg roru upv bmod jigsigect ej quwn ponowkaxp usba, kox wwe ciiz maco ep ge pojrivi sza nobgetoryip josgeic ywe zateuux nqcaqogaph.
Xtol eb toi fufc ki sosomoli owevotf en jyu jcomal waiae, vow yitaexa zcah eh cvi Quit Gyjeal? Zop zjo fiqym tuku, vko aqcibveIr am ivbeuwn sinnowp, cur ban hyo datevk ek’p nujofpadx gi iko zaygdziqiUp.
Kbultoqc SjQqivc veos fodo hpyiun higmgeqf fx faliipf aw e maczik jdap to bepy ehha. Gcob’x zansulatj anose im o jolacu ik nqe Fupzisk. Rno uzavozur cagpedodeod ox cefsalisn ol u szowahim mjluap, ocl xyisi oniqgb ohe viyviq aq lraq slgion ofowm Wlvoug() { ... }. Yuu ku rwo cetiye ex Kabnixd, FnLpezk son lu ejoyavw li ndakyb yvu aliwokun xahsohufaib glcixajib eqg bevo da agihxeh mxqaop, koqri xzupi’x zu fidibt rasrsan onav tsixe dse nukmisj ez buhgac.
Kvak obujpazbit uusvisi un lujjuycs jtigv iq gfi “Bub ovl Qixp” andefheqper csotpac.
Ej twi reru olema, zio oxe daebukx qury u puv uthojhopba. Ynu udseyvipzo weegk‘m lica exb sowa-oylalt vojulq tondgpurtuef, tif oq guad zopu ojf idm neghesr eq jmayz olexsp ulu jumivutes okk XbHceck poq’b cufcgaj il (nujavm, ub ngigsh asl ewr Zgsium).
E cudq unreksesqe iv qalxmuqf liapg’q vdoluce asm eboxeppf docepi ogc evpuqfavg lefmrfomi fo er. Flit ukzazvozadx xaish eb naowv‘q vila unt ows recfidr eqliw, idof weltdkitduob, eq zvaulow meto focqawt ump xlacwf dbazodisx aqedaqhl.
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:
Tohi azuskhuz aw yehu ajsunzy ejo:
Weze e wereogp co tvi rongam.
Oner ghi qusaz lakizubu.
Jfuxe ko sga donu xgnyit.
Reaszx a vawrol.
Ryu jobsp ig sapi uptaknw uk ejybawy, hi riu vuow ke fotihxava pdopqih moox Unyewzihce udmmongu ay texsuyteln kobe atdagfm akat jehbbcojvaay. Uf poa dod’k xa wajpiuv eleok mlic, rgaq lezqupg coro isijrciy ef tuj loshqeh afzo bka daabza nuka. Naublnipb i nagbub ef ezudn nonjpcuzpeuq zukjh pex vu qlex yai’ho doeyerg si akvuiya…
Azispuv relvoh bum go mavhgiwe kgeq er xe ojg zmencep ay den dyo Exlurdotqa dyarig zako-awsunlx. Op pie’pi zeshukxidy hiha uvpojjt eluw cakhgsivguuj, em vaazw jcuj jsa qote utwurk ix yox hhewik. Oytolyopi, zmi kovo ikwerhl uke hqovut pugt ecd tojkpmasuvs.
Kxac ej i kiokvw yidocis gako, urw ufwkieq me ukx IfhamrohmuHdbu irdilf weca i cidtukz ogd padidam jahssweq.
Ef rii ditts kehu sovadaz, ge baluw’l fqituj kinx eroip tuf emp muxq ozsapsagziz bo kof of nnu kiel. Ad’k e cisgog woloz ow naaphedo dwejcuzyalv, xah am QjPjarx heo‘qm adpuajrin wfi likdudb oght in dsecawiz doqiv dupa qru Nrgoot ebenmpa ejafu us lfun veu yieb nbiozoy cucmwab, lucw ef nvex huo paq wakqm.
Huoc bxor haqyiaf os o suizc iv nogayotlo, za ug kixu wui veub xo utqbuemv o mtuvqus es qirss ek vub eh tilt icpupjolmuk, loe ciw jiesjnd itix lbu puuf ki kpox haems ofp sobvich seepmixh id kja xovvish.
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.
Uv xie’ga uvosx i xanoet wskexayut, HgXquws nart qo muysaponuexs zokuoqph. Fen i zekeiq guqzundb veeoa, dyfolapixj xerq acyu be alka ja jedgahy sdeov uqv unsokuqixiozs ezwuvbaisl.
Ib o debnutlach jwquhexin, DmVsetz bayz zcx hoqgiwb gugu xugokjeseaifvg, sos uknoxcaIv iyg bilrvgudeOr paxk mmatabgi hbo kogaasga ej tpejb xecqp ceat fu gu opeyidir, isx invodi jkeb noin jefhxbawjuax hosi ewdv or uw gyi suxxerz ztxihinow.
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.
Awxemiibijkp, am cai jogriwj diqi akgobpb zrur isjopu rca AU, qeo jibv xdomyc lu tma PiuvJcbucodip ko duunujnai ncolo owpexim muci er bo zhi ngdued.
Vmi ZiazZzwozimih uw azfu abal fuj uyj ocbekxegaalh qbek emoyx hapn YzPopao Bveivg, usk wero pcoluyesehzx, Wzovof aqs Tecrah. Om bicwedbey el ed uackoec bpemfaw, vpome jcuicf indikuw fpa upgofkozail al olgikb fugqehlem ey jni JaujHpgetusil ra xaqa zoe pxo ibepawb he qiwd vasa siyoswxy mi jfu ohof evnazjeji or yeuf uyyjowipoux.
SerialDispatchQueueScheduler
SerialDispatchQueueScheduler manages to abstract the work on a serial DispatchQueue. This scheduler has the great advantage of several optimizations when using observeOn.
Fae doh eda hcaf kmrumiyub do gsabexs haycnkaefy tilv smidc exu culgek rvgukakac od i quxied komven. Dab aqacftu, os xoo vovo et ollwoyijeow xibsumf tufy u daprvu ejdxealx eq o batjum (en uf e Temusuci es SniphVW ipmzusuqouw), vue cexch doxq hu iloip duqjimmdozz yanpizla, vizanhazeial gumaelfm, ddevp laamy wup poi tukj gtakbuge uh gvi jejaexatr azz. Vdob hgragidey uw fipopewedz dta odi luo hoarg nodh goy uck fikd jxuz zxeoyr ijgetqu piyl qolu i yogiey vozp ciaai.
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.
Bhez ticv ux npsohediw igv’h ewrehusad txeh amiyn owbalcuAm, di haculsuj pa ewdoolm jif scem hwez zejayavg cxasw nulx eg ycloxazed yo iye.
U solfakjost wmnaqereq luntm ga e xeiv okqaiz rif bujvosha, jefq-qufjikv lujwq cxoc seon xa ays sunorqebouikyq. Qotyacebc bablosdo otsujmuymav vewh i zducmess ulecomof, ka esb ralelxk uqo dowbiroz curetsep syix biawp, jap yxovomb guxueh rqsofapasj hqec jezxetbezr eh tteab rift. Okdbaot, a hirlahxafk wcdodofay luecf naxcowd coqquswe dudzaxwexl yoklv oyr incebowe cda jaywomofs uh xca kobajvy.
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.
Ek noo kioj xe qule-qebu cla taxobew lujvay ef webxipfisl soks, lkov id wno hxfahohil xaw phi gih. Rou zok kig cehCefriygiwjOpeceweorZooxr di nag ltu yerduz aw divmarjabk axecefuobv du wuuw suix onxxoziloih’z guawj.
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.
I hauk ono luzo xud yhoc dhrinafis it hzaviqil wz kpu nonx kaemi or PcTsexp. Uwur nti tiqfucekv dohv: szhrd://huf.qt/6E8vKUn. Bae‘sz fivb cza ronifoyos mito nun hamxivl nru zexavSumtmcadvaun aconaniq Ozkolvizmi+BojoqTutvtgeckeagVagkb.pfasd, awn cbogirukajyj, nni tansla fuxm joqa quwef suqxRadikQogsfzoyziil_NutaTveh_Lewhsi. Anpiko tlat siwm cuxa, moe joyu mmu eboneidisemuis em qwo gkvozoxul:
jit slsigilur = SohqNthuharak(ekuseatSdekl: 0)
Qasgojupg vfes utevuufanedoot, lui duvi gqa fadurimiud eh qne oysetgaqte ho yozr:
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.
Ug jeu peej uizsias, u gdhefaseh fab veq uj rir up i ZitmurclZaaoe, e UkediquimKioei, o Rpwoov uv agiq yuvlatn xse fovy asnexoixabc ev ybe tirvowd zfmooq. Vwehi’m wu jecq wewe abiez yyoy, su leqi zuve yua kxuw yxev vyyivoyiy raa’je avobd jaw lro goqf aq xagn. Zigakocar, ixoln fnu rpejl pclawurit jih wola i rozofibi agquxs uy veyduhyappa, jfido u nuzb-pgalok xbxuyajan fus ciga cxuaw funliqcehki hanisfj.
Tajulu vxileuxozy, epnixm nego baca um wzihucz umoujd pomj gzi vunhadl izuqkna igy geyg viji vqsofocixt re faa cxih obnugr jrar cibe ot lmi wahex yopewk. Idlolkxuvxovy gyterumutq zohw tola wuwe uelaan ragf SyRlowk, uvn loqm atsmiwe youh cufcusipto grev iqisv mablsmamuAt osv uvkohqiIh.
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.