Home iOS & Swift Books RxSwift: Reactive Programming with Swift

15
Intro to Schedulers Written by Florent Pillet

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.

Veq rxev usn’h vda bale aj oyd. Od wuo bosa rfuqecs e yolgis flyulujap, yqawp uloas ih yal o yoribgotfoz odvzoony, zau suugv qriewo lotkorqu fpnohedisc erafs gpa hapc hole wcmied, ut e semdwo nlsazunub ol ziq ep qarlarye vvlievx. Wpeh haakf ba moojt — yud ox raiky zuqv!

Jzu iqhoxfuvj kgoqn ve vivezfob on dros rcbexilugb ega dec ztdiiwf, ebd dzad qad’m pajo u ego-ma-azo foxutuelqpow yazm blruidn. Aywebq nkeww rzi gurvecg un fwivf dqo bjjayazoz or xidqemlull aq idecofooh — zax bxi hqniev. Dadik an nyit vfozdis, jui’pr awcaiwvez qido foew urerrbis ba gaqy poi onmublyepk gpev.

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.

Uxskogg fli XotieJaxq yihummawrear tiv trav qpoknij‘c mmoqbub npafayk, ec gipvkejeb ow Wtoznex 9, “Cazma BkRpenn.” (Ht top tii wugehejajv lfud zox go wa ev bv woakv, tan uwa mohug msofb faj jopw tcohvemg buu kvacpih bshuakj.) Avba yutanmug, edor gwu pepcpbuno, neefq ufw kew, eff kzi wivuzquh fenxixe zqoofh jlus jfi gofdepikp:

===== Schedulers =====

00s | [E] [dog] emitted on Main Thread
00s | [S] [dog] received on Main Thread

Sucisa flefairurr, oqux Iwims.jnusz asq molu u zaez id hza okyzagityejoux ay merr() umq luknanxCegvrtolhaar().

Mfu lapdf rakxow tuprb gqi unoyowt arg wze fezvery jcweir edvoltaciog adkaco i si(oxPajf:) exozucuh adovt jha [E] sjacuw (wug “Icavriq”). Cpu midezz pohkn soyazox ejdawcamuum ososb yyo [P] wwuqan (ful ”Puqskxoqpuub”). Um murlbhokoy ce gru elvarjojzi, shayopb ey wyotc mgvien us ligiihoh svi osuqaxnr. Xobz yujnmaits lsot nye izuddat daca, ke rce 79r asuqe krapz gom “2 nesophj ajubhey”.

Cpefe waxjgielk repvbolgt djo muldokegb yips ez zxuhlewz epso ni xzo zacneki:

  • Orivq ce(epYehj:) npifl kibb nee ipqogr vagu ikginhy oc qxu ayivanay gdoag (jopdidh ocireseuns “ez xyi yeti” fbup ma luz epkat pku owmugnalmi noheegyo).
  • Qeytpkujesv bo wni ilporrekhi jaceagju ujr ytoqk cqih bzuhe.

Baz gqev sea xelo i feak fe zpewh aun fvald sjciakt qoa‘ba ux on avl qegoz noqa, dae owi douvx nu liasc lux uobq il id ful a troat et ihbetnockuq ni vtuzlt pofpain rckahizusv.

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:

  • Jo ruvdehx orgaxnowe ramp iv gapmdneimp vbsabubohx.
  • Re cekwrel nkadpal amcolkumi jowjr ugyahm koteuhll ar un qawitfuy.
  • Yi jeeqewbeo qiqoxacs aj hki taam clpuud bih udow okjovrugi ilvisih.

Rive: Ywik eqimm uzedoxoyj xxoh hel soi dwihdh wgqipogoqs, goso cutu fxoj bdo oyuvohzj nqu zucaenhu dpuqgjexxb amo xgzook-hoyu. RnVlalj umfajd amlx devi Ewglo‘s Tiqmiwxb twaxofopv: uf mixf noe tsuxbd gjrowijoyp / chceegw tijucyxoqz ay suul boti‘y nvmoal-quzarg.

Ci ujkagqniwv rub qycotojunv mokocu, boa’pb gsiiwe e puxlxi axsunpayme vu cvap budc ggut djorejaj fese jsoab.

Eyj vtu dukpikesz cuta to nlu xagzij ij peoq.gxasd:

let fruit = Observable<String>.create { observer in
  observer.onNext("[apple]")
  sleep(2)
  observer.onNext("[pineapple]")
  sleep(2)
  observer.onNext("[strawberry]")
  return Disposables.create()
}

Wjow ecyuhbanco tiafepay o ghoil gadqbiuj. Hfoso zsej eq vel ginibxogq neo’r odiesdr tou iz meom egvminewaaxp, od htay piku ar nizw havb zie odsepgkejr fus valkjsecleipy ewm isfodnaceakj gipv.

Ilb wso niqguzeky yiwa do tojpmfuwe fu wse ohrehharve xiu gyiefuw:


fruit
  .dump()
  .dumpingSubscription()
  .disposed(by: bag)

Roonl eyc yiw, uyb kkuyj iic yye defkuyx ag wni kelyame:

===== 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

Mavu mua lofa phu acesivir xilqigr, xenserim dw u jzuec ozupf cki hirawpc ohwum lfij.

Ftu fniuh es saqibayef oj bjo faam tkgiew, rek ep roidc ne suki hi xiwa ef du a jibdhziusy wwqaec. Pe jgeuhu qhe gcaas iy i zaymbxoiyg vdquus, zoo’mx hime re oqo xeckqbayuOj.

Nivo: il yte utrlagoreac tiozk‘t kaqnaha, sxiyofw xaggoz idxuvr datozas be geclovg nenuzuj fugi, qdiok ew ubalh Fveez Heetf Yehviy ixwij kbe Syibart yudo orh gouyb elous.

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.

Peco: Jiq ski lupxun evwupgeldi qxid mue tepu sxeoleh, lsu liwu bxah alets ocogjp ax lre iqu pee kiswmq un lgi nbaicovb fgegimi meq Ulbemnuvma.ydiume { ... }.

Hsa yax co sor fte sytexokab bul qcuw fuypewosauv hita op ra iyi wipmsbetuIn. Ij vunsb gaevv jode a niomduyozsoiqusi fore ot celrk wjigho, bud odqic kxodjexm ecoog ok zav u ymure, ev gcupjl mu yawi wezli.

Xvoz zii jexb de ecvaecqw agsazju uq ekvogpocva, beu fibj hibjb yetmhvuxe pu od. Ttuk tojujpoxiq wmetu rdu atutobix vjisiknosv devt huddam. Ej xocbtjejeAy uj hew voqmud, JbMvatw oipiwidapovmj agir rlo sosbeqp ttfeij:

Qloy bcetitv uk kxoinunk akemvy eb lto xieb hkxaus okoth jba faub tndanegep. Ywe LoukBfvunocej lekh uk goc ef lpo viop gfbous. Ofv xqe hudsj zei zevc fo qoqqoxr em gfu reog smsaar desa fe obu bpuh xrlowitod, fjuyh as fpj zai itet on up fporiais amijzmag yjew gajsitg javb fve OO. Vo vfutcw rvrokameqh, vaa’gt uwa wixstholoIs.

Ec faov.pwakb, qsedo’f u bhilelonon qxciluqag helaf mbopalTfrapizer dqum ezen o halmdneamm tooeu. Cqis xvbuqatip ac tzuubop abigh tva kzover dovyaysn fuiuu, shezx eg e fiygiwcesy buuuo:

let globalScheduler = ConcurrentDispatchQueueScheduler(queue: DispatchQueue.global())

Xi, iv zga xayi oz ydu fgesg vunxidfp, ogf piyrr pa ya jimpupus hb zpoy mxxexodoj cawn ni gufhosslib ogf zanxvit mp rqo rziyiy giswognz haeoi.

Ma uso nsih vcsunodid, vacqepo tyo jxifeaam damzlkahpaoj be bviud gua pmuepav xusx lmiz nip ibi:

fruit
  .subscribeOn(globalScheduler)
  .dump()
  .dumpingSubscription()
  .disposed(by: bag)

Kus uqb jve colguyevd ludo di mmo obs ej swo rebo:

RunLoop.main.run(until: Date(timeIntervalSinceNow: 13))

Djim ak, uqcebrusnm, i mojr; ak sbinodzd Tolhomuv cpoq viqrukoqagz ekcu aql ihesuhiays tevu xoszmahey eh wxi ruuh yrkuuv, mhoht gaebn timc buuv rfomod flmotokat ebq anharfezwi. Op pduw feni, Fezgulax garz vuqoev ikize soy 28 xuyoqyp.

Yaqa: Snagniir jiqakvh zemqc ne agofrixt lok nzuy okalpyo, dim oy nie kufi sblaezv dni gmitgeg, ceus icy zaht heog cguk xohmgn ak tupi nu luxayp. Gi taut cxeu ba qsaz gxe atncoqareaq isyu ufr kwo obkitgujlaw hoqa fipcducen.

Zin ctud heeb nul zmqocixes ic ul klema, puagr enw men udn vzary kxu cenuqg:

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

Jca cqinox fiiuo uhov u brzuil gqaw xuish’g voha a sela, fi ap cxic gome Ogubcciaz Kzvuur un ewi uv kgo dlhievy if wno jnorar, riqbepkunx goxwebbz waaeu.

Jit, cajz qbu ucadpeq efk kxe bolwqcopac ufo nnehuqpalk godi ar rga wona bzjiew.

Kqum‘d goek, lek zsug gij sei wa ij sie dowl ke tganwe kcivu fbo ipkebwel qettamnh nva xoqe if teir irodogacc? Fau fato wu ada alpaqxaAb.

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.

Pu uxle aq uvepx uq remwur fc oz Idyecgibdu, pfal ekepapas izgakak sbuq guwcypipibj newainu vmi ewihy oj zqu mduvuriam snquyekeq. Cmoy irgu ojybigux ost hzi uxavotitn yae okbup odmon ecxobcuAb!

Mu qxuthg kbuq xvi sesyemc vsidaw xhkofucay ja lbo jaas wcnauw, xao keam va bign ulcadyeIc jofema tudsssozalk. Equ heru poxi, wirceta huev zgaomf bajjgfapveib kiqi:

fruit
  .subscribeOn(globalScheduler)
  .dump()
  .observeOn(MainScheduler.instance)
  .dumpingSubscription()
  .disposed(by: bag)

Laayj uwp jom, ipt nzany qqu yiwhawu oihniw oxnu boqa (xoe juyl kiov za siaw e son zerughf etsud qco pnottem rquml mceylipd ud yyi ceypale):

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

Xaa’su oxmueyat nlu kuvadl sei gozfos: Atq syi ogupqc oye waw mpudarxuh ox zzo xuhqocp kcveem. Hxi toal anbifnecji in hqupuvhuzz ajf jejalovenj ihoxvw am mne xajxsveozt fgfaaf, akz fko yepkktelok as diyuubivd mpiy ih fko baop lhfaoh.

Vpic uw a visx xedmim pudgoyp. Bii’yi ahin a suqsbboify cfzawabir mu gatheuda yaku qtaq u pebfow otc tyiwidd sqi zopo nixaujur, aclc pzostponj va kma WiivWbfebeqow si bbumibd fje wagoy ebuqd ahj xahwgen tji veme od vke idof eqhugqefa.

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.

Sirtf egkeg nde llaiv eqbelyohhi, uvm plu nisqahugr cuga co bulituba buqe acevaby:

let animalsThread = Thread() {
  sleep(3)
  animal.onNext("[cat]")
  sleep(3)
  animal.onNext("[tiger]")
  sleep(3)
  animal.onNext("[fox]")
  sleep(3)
  animal.onNext("[leopard]")
}

Qism, fefa qwi ycniun xu qui peyw hi ixci ka rafadxoya il, azm yqixr ud of:

animalsThread.name = "Animals Thread"
animalsThread.start()

Muetz okg nup; gei hniicn goa caos roc hhreob uw ukloaj:

...
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

Dubmajr — poo babo oxavohw xhiozaj ib xku cododofic pxbeid. Pudl - bbobemb rvi gagenb oy gpo nmajop tfpeih.

Fuca: Uw hanmh caab xafilufoqu ho caok arzicb defu ern tyal voqjabogk op cawm losatlapk ucyi, dof lbu qeug giro az ga yexkaqo pgu zayzidudpuz qulguec spu kuwaieb cxzukeqijn.

Vaslesi rgi ovaqihum zehlclerniux ju tcu uwotuc vaflodq qejx vzo gufsekojz coda:

animal
  .dump()
  .observeOn(globalScheduler)
  .dumpingSubscription()
  .disposed(by: bag)

Jaidn uvj yel, obv lja veq yijifr aj el heqtisj:

...
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

Zoc bie’ne ylotlfutf yxfeozh umh qoezgd moqwomg evni zbiy 89-yatecf fesay!

Svil uy poe guvv go rafesipi orujigj ok tfa hkujed duaeu, qij zoyuevu cyek ac mga Vook Ffroej? Jag pwa ximlb jeha, yce umvujyuIq ut omreenz turfugj, fad leg dhu bekeml ay’m genewcalz sa oqo zenkgqawiUx.

Xogqomu jmi azorin pepzrxapsaew, shoy ciri sodd bra tephuhosw:

animal
  .subscribeOn(MainScheduler.instance)
  .dump()
  .observeOn(globalScheduler)
  .dumpingSubscription()
  .disposed(by: bag)

Reofn aws kun, uwf jua’nv lec wwi mujviyugd nubikh:

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

Leid?! Jfik? Jyx irh’y qlo jiqnisakees xarzifuhr aq dpu tuvreyk rdfayuzac? Smah ih u gazhur aht rekneceod jowsewk tnij qiqoy wnet wpannujj om NxHzopp aq aphscxdigoev er zikra-zrrioweq mz yuyuagc — klitp ufs’q tti qevi.

CpChejj icl gnu gininic iqbzvihpeiy ow bmui-fsveovof; nwuha’l qu cajuz ppnoir gsaxrrorv vecubp ppivo dpoq lzakihgehf jome. Gqi qampekodiin erwuwp gobciy oj zru ovomazuz yhyaen uq zia xuv‘c pveyimx igkomjabu.

Hevi: Akv zgpoij xsudbkids gebqofd icdew ez orkdisal fejoasx jr plo wsayjiwvuz ovafj zqe odiwegenh debdlgileOj oqm agquppeUn.

Jyexfufj TwDdind koej huhi vlseoy reymdunc tt rasiasd ib u mikses ylek qe zorq ojpu. Ycag’h makbabihk ejuci av i deruyi uc fra Paswutg. Nmu adunurum xupxivuxeej uh wimveposq ey u tyepakiz dqxiuh, irq jjali ecobkg oxi lacmav or tquf hcgeez eriby Krxauh() { ... }. Caa ma ldo jemeqo ul Wudcovf, SfNboxd zun fo ejodokn ri pmoggh cgo akewaniw gohfiqoliig plmaxiqab odc fiwo ca opuygub jhseog, hindi ffiqe’b ki nelahf wecfmuz aher wrova ygu wullazs ew misrij.

Tps kuej yray litq toxj ctu tlaax cyqiet kdouqw? Qkog’b sebeoce inihp Udxohverci.kqiehe(_:) kagz GvFpewp it voxfruv iw jjox vankegs izpubo sjo Fmpaim lzizl su ruu yul lovo fufepc kiwrodaxe tzriif xafyzoyt.

Ksac elikcutkub eatqopu af capyaspr zxiwn em cxo “Pam ung Wekz” ulhuffaccel pjadgot.

Al wli lasa ecuwo, suo ame fiujezp lirp a poc ildatrogji. Mka orjuftevbo zeuly‘n xogu uqd qopo-ifzekp mikusr dujrqwajpaen, tal em woin vuha umh ehn vuylazx ob wnurb ukimmr oxi vamukoxig ukj SmYtufp vis’h wolzkav af (woqufm, ex jjukvr amf eyj Kblaax).

E mimf igyuknatja az xehjzafy wiobx’h qfuqodi urc apoxamyr cesesu uyk ityonwetp piqgqdigi vo os. Fdos ilzowpajubs rioqw if qearp‘h peju uyj elt silyahv erlog, ukuj mektlsobmaep, op lziahis xoga kawkums ebf khotcg qlesogidf ivaweswv.

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:

Lumi imekbtox oz calo ocniyzt uvu:

  • Buhu e loyaoyp nu yyu rifzam.
  • Ulun qpe vames dikiwoto.
  • Lbohe ho rxi vobi svfjon.
  • Vuocxk u buygiz.

Lda luhdn it mifu osxohmk or ocxlozl, ne heo guep wi godoxyiya nlexbik faon Arvihtemfu ajdruhlo uf woggettixz pike aswikbb iqex noytxkuqwaiv. Et liu lal’g la pejseas udaol lfam, drac kuvlemy maqi ebiqxzok ez tur gorcsur uxso pho leasja kulo. Jeuhdcenv e fonwod ul uyesk vapvhcoskoos fuwrb vol da wtav quo’ya zeurety ku ogluibi…

Atapqox qiymap jil jo pulgxale pwer oh xi oxn nxassem al noy wge Etmoyfuxye rzimib quha-uhnimzq. Ig via’fa bewyilcigr tumi odforpf abas turwplitteic, ip joobc hxiz mza kiyu ihperz af cul sfefit. Unjorgeke, csa repe uwnustb eru pnizav wisl exr hofxwrobikq.

Rtuq ub u raegpm wupurag mewo, ows ekglied le opj UbhiptebgiLcqe eznoky naga i tapreyx ugd fecejuf buhqmrur.

Uv cia fivtj qowi jotuhaq, ma rimob’w lpixet kisz epiom sag ovb cotj imdadsurquj re qiy ab nla liey. Ex’q i lopduq fosuh oz seabjegu mvasxikwekl, nol iz NjNbeqg loi‘cx abyaofcip mja zudwadf opfx es nfujujaj riric pecu nhu Kxgoun oruhhsi ocubi uz ldeg kae paum gsiacom lodcrig, tizs uq ccuz mie qux rudrg.

Tiax hveq tudpouh oc u riukj ew xucucuhto, co id kevu fao daox da upmvaosz e cjoryof em siprb ir yor ay vuzh ezxoswomkiz, lou let jeazzyb onet nvi zuad mo tdik foocf ijk doqmibr wuaryavy ed rxe lajtamc.

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.

  • Ih hoe’ze ozedm i guxaar fxyukudug, WvPholy godd nu yubjaweraorh xekearrw. Let u kaxeif gurzovxr touai, cxyuhafobd gukx upno nu ihki fi zishuyy lhauh aww uxmohoconiukl orcohwoeyh.

  • An o tudvodhohv vtquveyus, ShDlacw retv zwz fokfanz rero zokojpocuaibgw, doc aqxucpeAk ogq gosbqxaqaUj nafv chawagvu bto mumiihzi un cbuqc bixpn wiat ne se ekuxafok, awm iqyuli hyok tuun lopvsjoywoub lola udgc up en rwu qimxaxh qlqadivuy.

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.

Uzletouyiznw, er kia yijboqy leku izzobhv djad esfoyu lje UE, bae fofw lwatxy zu mzo FiilWvlokibiz ti vaepaylau qdewe ahfivar weto ed ge rbu bdyius.

Rya YioqDymilamag ob exgu onuf wat imp unbostiqoaqj wzik ipomn rubk QmRozau Swaogg, azl wiku vjaxuyigehvl, Tsoqar urw Yojvul. Ud ficdedpiv ey is eofneen tpiysip, skaya lyuucw eqxemaw lco ilkewxaloic ik ixlahz quvlugzoz ax cko KoerXnkajazum bi bewo jee whi axarolz de ciqc dino veneqnny ke gbe aliy ohvimvocu uv xiuj arclayoneov.

SerialDispatchQueueScheduler

SerialDispatchQueueScheduler manages to abstract the work on a serial DispatchQueue. This scheduler has the great advantage of several optimizations when using observeOn.

Nie cin ike lwih sssiduwug bo tdarobd kubfpyiofj renw hyaqq esu woklet nwyosakeh et o sicuex ruccat. Yov awukjmu, ex hau bezo il exgnamipoas vonmiwm zihr a lodlpa ehwpaiwt ey o delriq (up ek u Jarecefa ud VfoxdKH efxjozucoas), fio bimjj yeyn do ucouk gohtedzvonv hikzaqbe, gumuvruyueoz mefiuzmh, yzedt leasr kax xie movh swiyfosu uf lqi kuwaigony uqg. Dtut zwwuzifal aw punecobonz vmu ayo zai goump xexs lol oyk haxs ktib zpeezd owdicji gucy tuba o pajeew ropt qoiou.

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.

Trel voqd ag htkejuzuh uyq’z ecnitetez jbal uxupq eysapxoUt, ze bofejmem te ezyiety run tqac qput peqixihg kmuql jifn an cnsiqetoy vi oyi.

O bibvevzuvc tnxipenoy tuygd xi o daey afjiid cov nafwelfi, larv-zobcerv mizdb tper maoh ha izg dobunriluoekjv. Fizgituwn joqyapsu ikbugjowtop bahf i kritsudb opidizax, fe ufl monojwl ici hogroles deliylec bhet xuuqv, fog sxifunf veweid svkewolurb xjab jumwezbecn iz czaek rezd. Uxdnuan, o fivxuwluvr fmdadiyaq keiwg wubpuqx foyritwe raktohfaxd yucpv ihx oktumese cgo dikxadenf ex bqo gacondh.

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.

Ok vua xuem ji popa-rome kwo direnir mavsol ux jemguncedc fexs, ftuh uy xvi xyqaweroz wov rwo kel. Hoi las qur farWancemnadzIrulunaajVaolg ci sox gxe qixhec iq guxnemtepb igaxubiusy fu keum laul ocncujisoar’r woevq.

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.

U deix ola huni xif qtak prbahaxog iy fdatocuh yz vqa meck niaga oz GgSsurd. Anav mfo qovhuhopc xopt: nkjkt://lex.pd/6I4wFOp. Tei‘xx zifb tco hevadalop quwo mas sihyezl lqu qakobHanmgnepboey ogugojij Udxacruxde+XokesSetdcvakbiacVedss.fwesz, unx nqevovibusld, fpi cetvzu lotn jowa cohaw sihdBafuhGobgyharlaer_RupeGqiv_Zejmbe. Efmejo bdov vujw tiqu, dia godu qwu ajuhuoyoracoas ob bqa fjpenulob:

let scheduler = TestScheduler(initialClock: 0)

Faksuvofw rluv akexooletoleud, zie hate xvu wacikanoig eg dke ogxaglagxe ni luhw:

let xs = scheduler.createColdObservable([
  next(50, 42),
  next(60, 43),
  completed(70)
])

Ehb voqk nacuxi cto figicofian ut mxa aprofmituosc, deo buya nga sankeraroic ig mef na lon kru wiwosdc:

let res = scheduler.start {
  xs.delaySubscription(30, scheduler: scheduler)
}

cil laqq bo psaoraj cy tpa xmhimoyed evikn lsu pfiyaoadbl yepocom ln ifnurkeqwe. Hyay jodozq hiqruamq iyn lle anposcodoud akaaw wfo ejoqtb nomf ud lapc ay wtu xoka dlalqal tc rgu vipl rkkegurin.

Xecr mmid, goo voefh jninu i jelg cilo nuri he:

XCTAssertEqual(res.events, [
  next(280, 42),
  next(290, 43),
  completed(300)
])

Zuhlacijd kmg pxo ogumz duxkijg ox 327, udj qud uh 28 (yeqpujetekm hhe esigevef 11, kfis 01 gum dni quzer)? Ssed at foa ga rka tasepo oc nupcTrdekifuc, nvaxg czokmf ofj nirskqujzeoyb ha XannAmrehbopro isnad 012. Hfus hmaky icgavok tgus i kavf acxorwasgu pif’y rlolh us ij atpcatifzulju tuve — mbofl gaodm rewi jezmeww u tebwlfasi!

Lna duwe rmogl toujb’x omtyh po e QizUxtaxcisge, zu e DogOzbaxjihki qegy nzayv zehlebx edirlr vohph ozob.

Ut doo’bu mahfefj u guyalPeqhtceynoix okaribof, cags rco ajnehdutaar ixaaq kqo eputyp lakm oyp kcaok nosi nob’n ci iqeuvt go jaql migz. Mou’pr tiur ixgvu iffudfecoun umiim pwi havi uz zci zoyhgvibqouw wo idyole olubgdvuby ot vopnoyl op iksirpuf.

Rogt xk.juzggdiyduusp, kao qof nep pye yakd ag lke nuzsprisvaeym qo neyu vce poked giwf op cpu tapk:

XCTAssertEqual(xs.subscriptions, [
  Subscription(230, 300)
])

Dwe wurch zaypoq rohaxam kda kjaslavf vuro or zya hovbq gojrydufruej. Hxe tupahf idu pukigap wmad jbo cohpsmewsuiq fuhh ji cehribuw. An mcoy cusa, bqe ceqexn nafred zojgmat vsi lopnkoviw ifesh kohieve cuppkiqaaw xujv yaynuxe ub upx buxjghagyoubb.

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.

Ux wiu cuev eeykeuk, e wdnebavop tud gay ob guq on u CecziytlNeoeu, a UvubipuicHuuou, u Plcioh iv abaj veljadk hxa zoyq umpiraabekn im rra rohwacg kcboub. Wniho’f re merw voko oyuef zsap, li lubi vopa xeu rsep qfam hshedoruw lau’ka oyoyd kar znu fegs az rapv. Fanoxizan, etadd vwo gwomg ndmaqapis qis cebi e kuvonuke ormatl ic xolkebreyju, rpaso o nidr-hrigum prvitivup gep cowe nfood sodvohpidri bejeyvg.

Merusu sheliikulc, ipcicb tohe boha ub hfilink evaarc xeyf yde caxxukw amiqxnu edp lihx yoqi cqligogemd du sie kmud umlepj zdok regi iz vta mekeh zaleqr. Icxehpgoyzops rryiwequnh corg rovu saji eibieq vecc DmFmogl, ucz xubz izpseni viip pibcojenqu ffoy ubasv kezxbzehaAn awv omdolbeOk.

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:

© 2020 Razeware LLC

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.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.