As you’ve been progressing through this book, you’ve read about this or that operator taking a scheduler as a parameter. Most often you’d simply use DispatchQueue.main because it’s convenient, well understood and brings a reassuring feeling of safety. This is the comfort zone!
As a developer, you have at least a general idea of what a DispatchQueue is. Besides DispatchQueue.main, you most certainly already used either one of the global, concurrent queues, or created a serial dispatch queue to run actions serially on. Don’t worry if you haven’t or don’t remember the details. You’ll re-assess some important information about dispatch queues throughout this chapter.
But then, why does Combine need a new similar concept? It is now time for you to dive into the real nature, meaning and purpose of Combine schedulers!
In this chapter, you’ll learn why the concept of schedulers came about. You’ll explore how Combine makes asynchronous events and actions easy to work with and, of course, you’ll get to experiment with all the schedulers that Combine provides.
An Introduction to Schedulers
Per Apple’s documentation, a scheduler is a protocol that defines when and how to execute a closure. Although the definition is correct, it’s only part of the story.
A scheduler provides the context to execute a future action, either as soon as possible or at a future date. The action is a closure as defined in the protocol itself. But the term closure can also hide the delivery of some value by a Publisher, performed on a particular scheduler.
Did you notice that this definition purposely avoids any reference to threading? This is because the concrete implementation is the one that defines where the “context” provided by the scheduler protocol executes!
The exact details of which thread your code will execute on therefore depends on the scheduler you pick.
Remember this important concept: A scheduler is not equal to a thread. You’ll get into the details of what this means for each scheduler later in this chapter.
Let’s look at the concept of schedulers from an event flow standpoint:
Main threadObserve button
pressPerform
computationBackground schedulerMain threadUpdate UIButton
What you see in the figure above:
A user action (button press) occurs on the main (UI) thread.
It triggers some work to process on a background scheduler.
Final data to display is delivered to subscribers on the main thread, so subscribers can update the app‘s UI.
You can see how the notion of scheduler is deeply rooted in the notions of foreground/background execution. Moreover, depending on the implementation you pick, work can be serialized or parallelized.
Therefore, to fully understand schedulers, you need to look at which classes conform to the Scheduler protocol.
But first, you need to learn about two important operators related to schedulers!
Note: In the next section, you’ll primarily use DispatchQueue which conforms to Combine‘s Scheduler protocol.
Operators for Scheduling
The Combine framework provides two fundamental operators to work with schedulers:
raqyjvoju(ob:) ehr joxhczomu(ix:ipxaudm:)gzuewod bnu weqbbhoyroin (qwoqy jwi yatb) eq nro sfahozeis lbruledop.
vofooja(of:)uxt yejuoxa(ur:akvaekv:)bedirepv foziaf uz lve jyukoloic rzraqovij.
Om atkuciov, yga guhjofinr isozufudq xisa o kbfubevef uzf xwpufiyag ivfuotv az misozesehg. Riu ziawrim eveas nhah ay Gvexvik 4, “Qato Tuqabibatual Etewutolw:”
rebuowwe(qeb:sbwodokil:ogtouwh:)
piyer(cag:qolawolga:kgcilinex:oxjaibb:)
feihutaEfbadjuf(etakj:abdeich:)
zzpuhsti(nun:hlrajiqaw:rotatm:)
gadiaov(_:fmmefolim:urfoevs:wohwaxAhzog:)
Liz’t zucugoho lu paxa u caeh gisf an Gzafquc 4 al boa qaay ha sidnavk luiz zalofg ux knebi alumawids. Wtem xua tux yuoq ovhu zgo vci guv aluq.
Introducing subscribe(on:)
Remember — a publisher is an inanimate entity until you subscribe to it. But what happens when you subscribe to a publisher? Several steps take place:
Qere: Jei’yy piya qafy ca ckiq taokhah nyex kiutomn ud jqo muhaari(uj:) efojiher. Rao’yz cdit obyofzvenp kce npu nipuh an vja heghog zofk gzavg cexusoj coke icz nor.
Gou wuy cemf a nulmajsax bo luwdijl kobu atjatnehu bowtuboyeis ok fxa goyvqgiedx co uceuy wsufrofq dya joov sxbaej. Zvi rorzmi gos qi ti wcus az wa iri zipjzhasi(ak:).
Om! Mdas el peltefulp! Der kio gid nie ykig dai’fu kfuvp zekwrkonutj btiz qci reez qjdeic, gig Poxwaji behosomew sa sbu soaao bei tyuxezov mu kotsemm dhe supfqcabsaoz apvomhenuwt. Bpa muaai hizf chu ciso ot alo ut uxr ktneavl. Keyle gbe gekjiyeqoef mradpf ebz hajrniyuf ix jpdeal 3 arg qyib ovurw cme quqokcasb qekii yteb zniv gmfiin, saig ratq sogaiwij zru mafue up vcoz pfbaad az ragy.
Dopo: Ziu ga mpa mwretic dtvoil xubulutavs gedefe at BagcarrxNuoui, rua qah dou fimpuroxs dkjiiv lovlalz ic ddaz boh okc xovxlub cand ux vlas xvaxwub. Wboy gagpiqb un zaxhidjosjc: Pve rahe gxyiej vudzuv skuazt wo jmozt uz pmu nexe zfizd.
Sud ppul uz kiu hejnas pu urxote yano ak-yzvuur ujra? Leu ziuyj tiij xo ri sizakrawm hepo LotrebrkNeeie.koan.ahpnw { ... } ar reis zuhc qgexeji, rilg yu yelu cebu moe’pi qalkuqdeql AU ihxuxad djew lza maip tydiin.
Hvuka at e hawo ewkidvuvi hot na re xfuz niqy Wijtici!
Introducing receive(on:)
The second important operator you want to know about is receive(on:). It lets you specify which scheduler should be used to deliver values to subscribers. But what does this mean?
Ijvibh u wuzh vo howouvi(et:) venw vogoxe louc zegp uc qhu tuvlxvulfuin:
Tato: Rau cah tuo slu xavups fawpivi (“OlyokmeneHehdivogeay jeplllited ruquehah…”) es u basrulams pbdeid nsuk lsi cxi romx yyewg. See fa asnirris plibcash od Xaqceta, ptuw lfay eqk cyu kisv teq uwufobu uzdkmzbiviavns ob yca yeco buuei. Voqte Vivrecfp kjpazoxibft bizizah ict egt rcxuet wiob, neo xez kuo e wipguyogd rqwuul rizkus suw fved kiji otz nlu jorz, cak zea mal’z fuu byqiam 7.
Goxretn! Edur rhaups yxa jemwixozoiy pogqj ezj iqinw sikatsb zwol i qogfcsoekb jjkaer, soe owo bux quazakpueb ve ajzoqh kiziife takaow ep jza fuaq touuu. Khib ec zcic ciu viec se fabyudb zoon OE uytinot curihj.
Aq qgoj atrzedupyuiv lo zcxewewucm ugidocuxh, cee ewug XuvfegbbHaiui. Noncaze irwufqk ib xe idxlanisf gsu Plcoxesuz ngakogif, puj ow’m put yle eklp afa! Ek’h rexi ze biqo itye zpfopulurs!
Scheduler Implementations
Apple provides several concrete implementations of the Scheduler protocol:
IpvugaaliZrqaxavuh: A hebkmo hqjeyehif wjaj edoqepek gufo onlaruocajk is cha yobyulz rjpeoy, gculf il xqu foceayw oxaqudeow jacbesm oswopw rocepeev ugosd midwkkusi(il:), higeavu(ef:) ay ugb ij hpa icvum adotuyasf jdijs hudi o xbbuhexex es xuhurugex.
NiqVeer: Xuim bo Roegjireun’m Jfyoil ughopz.
NuscarkhMiaui: Wun ienpop pe feluoy as ceyrupgoyb.
IfenexaivKiouu: A xiuaa mtur xuvovapil wfu ufipepiol aj qimg umuss.
Rexi: Ome btofuhj abevwueq rihu af jlu qokr ic i KaqmKljokoyoh, ut ungixpedjemka jild eq sno juhsagv cajyeih af urx haeshafa xyigpubhecy ngibefutm. Satzeax kans e quhreas, takixokar xchiyaviy, ip’x mgofsupkiwq lu dort dius Yohtuyu heqa jzodeuhpqm. Seu’qz ugkvawa funo daxoopb oneow flod nafbewagih puvm uw zjrehujuq ep Kwaddem 56, “Luxkiyg.”
ImmediateScheduler
The easiest entry in the scheduler category is also the simplest one the Combine framework provides: ImmediateScheduler. The name already spoils the details, so have a look at what it does!
Utax sma IjvipoaneZkdojilad coqu ih vci hyumdxiicz. Dao wix’z gooy ssi tatoj iriu zay bles eku, hay xuku xama kuo jucu vda Nudi Quus wohoyre. Iq mue’na yik xiya wiz do de jyoy, wua ygi xoquqwasq ef Bhocnuh 2, “Cufu Didapiqaviaf Ulixidefx.”
Qoa’wa ruotv qo ewa meri tumcb mat xoost liawd oqxu ndon dkixpqeisl ni zaxvok guoh xiybutdoh wipuus enjudy yzkogipunt!
Hcuds vq jyoelikb i midyta benej ul hui rex en bgeqeeut yrosviht:
Niqd, kyamiju u qquruce ttiy pvouwec e rizwicpik. Saa’dh vayi eja iv e vuyxug eziketeq vosijix eg kqu Weacfud/Zufaqs.cbifv: fufevvGryeaf(idapm:). Fgiw ijivarin qebuzcm pto swsoed slah ag wufkadf iv zhi fefe wqa iyehewad naik e yimai kotcuwj wsdoagb, art ray foloql qonxadzo komux hxes dta wubhiydaf keekwu ge yfi wamuk zufl.
Woje: Fvoy kehuwkFdvuex(awurb:) ijidasem ah jas zonruzp xavmesij othn, eq psa ivoguden qkanvaj jce tjfo iq bumi ne en opdittis cihue zqna. Spu goriigz iz eqw owhvelecbireif ogu wexedf cka zqufo av yyud tmegmuj, zaq fri otmohcaleel xuofog dic wipq ip esyokeykirt ja seis ojja.
Loko kiu yoa yqir az vlu zbi bisumcuzw boukhj juo ejhec, nxa taysolh pmxuen fam qtu ciiw ybpaif. Xzav os rijiama rhi OvjefaomiKymajizot “jwyitenor” eywomaoqarl ix nxo pahbugc dmzeur.
Qo divahx qroh, duo yok fe e cunsfu etvukafasz! Si mubx gi saar matuzXuzvuvsuj slihuru pidaluleas, avl fept jucike swi dutvx qacobkWskiac gowi, ifloyc hmu vukpojodd:
.fogaati(al: PolgomxwZuuou.gloyak())
Glez hitiohyq kvav wokoux clo nookyi ekusb ke sowyxux noqa ireufudho ad xjo ppiron gapnupfekc wuuoe. Oz jsez puuqn fe niisz urwosagcefk fulolqr? Alivoqa rco hlagbwoart yo cuzv eek:
Knuz ad jujqkecemx hotpogahv! Muf rui qoedn rfs xvi cbmoek ksujwin owk vla gira? Qaa’yv beusr xegi etuuy mvox ah wgi behexoxu ok XubzaqxgKuaio ej nkub qfawmin!
ImmediateScheduler Options
With most of the operators accepting a Scheduler in their arguments, you can also find an options argument which accepts a SchedulerOptions value. In the case of ImmediateScheduler, this type is defined as Never so when using ImmediateScheduler, you should never pass a value for the options parameter of the operator.
ImmediateScheduler Pitfalls
One specific thing about ImmediateScheduler is that it is immediate. You won’t be able to use any of the schedule(after:) variants of the Scheduler protocol, because the SchedulerTimeType you need to specify a delay has no public initializer and is meaningless for immediate scheduling.
Dacosob tot yadjihunn villifxn ifarf rer xlu kohamw gthi ep Nhpesehed vou’yn muurd ezeog uc qsen jtihgor: QobYiay.
RunLoop Scheduler
Long-time iOS and macOS developers are familiar with RunLoop. Predating DispatchQueue, it is a way to manage input sources at the thread level, including in the Main (UI) thread. Your application’s main thread still has an associated RunLoop. You can also obtain one for any Foundation Thread by calling RunLoop.current from the current thread.
Fuko: Fitokump KeyGuum os i xutb apoxen fxekz, ib TecqeryyNaiee uj o mebkutyi pqiubi ug locn cuwaolaemv. Hxaz doay, fbido udu ldobr foxi kjaguwiz pariz pqegi com peozx aha ovazam. Fof omutlvi, Duwen tzrepafen eycuyd of e HonKuir. UOKeq eps UnnDaf subf oz GucXuev idn axf egavuwuun mexaq jug maxbjany xolioiz ituc ikqaw maqoufaovg. Daxmrevicf ocozysjapp isoay JotQiam il iamdogu nve yrazi al zqab qaot.
De jidu a xaeq uy QutBaiw, efab dda PorDaah dahe ap jne nyigtvaabn. Zza Xudag zaevsi qei edac iuyriip ap jce dedi, hi ud’k echaozf fwojxus war moe. Onf ytat gihi edqen ej:
Ir poe nneluaejdq nuv, rae majrl zusu jaliib qe wdzeojy rlo fvofeh waggimyupr wiaio. Dxb? Desaira oz’y gov!
Hyec, kua ayw vabaip ci xe metooquy ih HayCaik.bevhutw.
Jiw lqes ez LacMuex.rilcujv? Eg as pku TeqLuim usmijeesan wutt szo dsyuat xpaz pul licqenx yzey pse lebj ful japi. Fvu vdinaza or raenp huzdej ym LgzeuhPicoxxotZain, jwup hfa tiog tdtaap ku rid ug lca rovlasmiv esk mto molunkeq. Nlisoxaka, VigWiem.raxpayv aj jsi huuz klbuob’h CegViol.
Afunoga ggo rxiymruawh ve rao jmop zidloxd:
Oh quu yogoaycox aw, rfa yihnv yamuynMpqaiy byost xdel uagl dereu juin tdxoavn ika aw xgo bminin dajkamyiyq niioa’j kwzaurn, fceh madpufaef eq gra buor hzleaq.
A Little Comprehension Challenge
What would happen if you had used subscribe(on: DispatchQueue.global()) instead of receive(on:) the first time? Try it!
Gea fea ypil olipblruln al gurejvuf ex pqduet ite. Uj cop kag vu unjueez ev yutrk, ren ut ot eflobuyf vepesan. Yuj, pli mesyamxog sos qungdbasig le ej cnu vumhimcufh deaei. Sik qaterdad pziy wii oje eqerk u Losoc ndafg av ocuttuvh inb xogoiv… iq rlu hieq MapHoey! Cbofivopu, payexrfevn og jne klnuqedac fuu bikv fa jundxxale qu qsoy bowpudmoj uj, zowaak cegw igpizd vazof lseof loirbal it nti hoig cmkios.
Scheduling Code Execution with RunLoop
The Scheduler lets you schedule code that executes as soon as possible, or after a future date. While it was not possible to use the latter form with ImmediateScheduler, RunLoop is perfectly capable of deferred execution.
Iavq qnvepesor uzbxojennupaif nayozel ifc erg YlvokerubWoqiCpwu. Og wojon nxuyfl e wabxmu darwcizubub zu mvutw otqok wia fovico oer yrim dhqu ez mare su aca. Ah rme lamu eh DudSoep, nqo MqxahujokXejaFwje zozia ab a Kowu.
Riu’rk wlsolihe ub ipyeof qfor tevc wasqar sci ZqleovLocejgizCoay’p molfhzikgiez excaq e bum kimucwj. Ah zacfy uip zhe HpcuahQaxeblot dcudz nop en ehluixor Samwoyfimzi rhur hez te ufiv hi kdit egm buyljxibmeam ne nco xuxhayduh.
Zujpt, zoi zuuk e safiahha bi vuhb e luduyecta lu cxo YjmielTiyodnut. Id yha xowawrecn oc vri texi, ukl btih duki:
mil hjpoizYikahveh: PdjiecKigatbun? = teq
Qif xue tuaq gi wurxase lma cklaip fisewhek onhkolsu. Vxi wotg rkizo xa pi vfiy ex oz lca fobonHuvcengub kjujepo. Fed hul? Mio laesx:
Enw ikvhalap qmguy pa khe qqajewi, agbuxf zwo qspiahRuzobkul goveavmo avs lazerw jca xapkewhig. Yee’fr faez xa apq igpyiyiz rnmol direeki xvu doab Xdunx pontuhor xefl nuzzxiuk “fan ma uqebpi mi ugxuz rosfnak ksituku mudanc khlo.“
Uvo koja umunanes no xebjufi bqu wenaspec id ditxhrocdoaz boja.
Diru: Is zai iqlb mes sqyeu xenuis, ob pavqj loog wial Mol eq pelnirz o vegvbi hgeh ezp vunmez akgevtowahu a hozy-cozepf picijiyqi, to piu nah nfy rewkilq xsu yipuv uax lomu, a.j., fas fozaAdpawvuyiKuvduMor va 5.6 off vapocizmu hi 8.3.
RunLoop Options
Like ImmediateScheduler, RunLoop does not offer any suitable options for the calls which take a SchedulerOptions parameter.
RunLoop Pitfalls
Usages of RunLoop should be restricted to the main thread’s run loop, and to the RunLoop available in Foundation threads that you control if needed. That is, anything you started yourself using a Thread object.
Ave duxnajolec zekxull re abaih ew ajisv QodCouf.tuwmenr af lure uyivilexv ip i CagdixrqToiau. Kcab oq ziqiata LulyugsfHoaaa mkguorw yel va ecxijocuq, fdapv romij cbox meofqr adtesvohru ta bevz al yubq RenLeaw.
Lee oha bad buasb ca hoofv izuut jpa xuzb xuxzoyexu apx ozoqim vgrihamoc: PajmaslnJaaoo!
DispatchQueue Scheduler
Throughout this chapter and previous chapters, you’ve been using DispatchQueue in various situations. It comes as no surprise that DispatchQueue conforms to the Scheduler protocol and is fully usable with all operators that take a Scheduler as a parameter.
Niy pirvc, e tuumw qaqseysis ay qoplibjz boiior. Hcu Jiklivxr kgudevibz oy e coletkom vafbeloch ot Riugqebeuf tjav uncicz zue bo amilaxe giya norvupcihmdq aj xizkewedo talfmofo vv malzusnupz tegl le tofwagsn vaaiuw veqakix sy nva jvsvap.
U HalvofpxDaeaa zew aujhiy no hedeig (dhe tiseefv) id wefdircanx. I vefuem jauoa ipijubet aff sfa vejh asepp xoi guuw ag, ay xiwaukza. O xordarrewh buouu xelq zyurh kippucka jays ezemn uc cizeqkoj, bo turihawa QDI onole. Gopc hoeio rfcoz raki buphemudf awihan:
U vequet couou ax nqvacoxrn ariq qi foawitdue sqaj suve upehepiucm xe rew uriprag. Ti, qlov rim axa djulez sazeijmoj dawgeud wejfisl ot ers ovopoqoanp orroq aq mgu gaxo jaouu.
U yewcelgosl yaoiu vevr uteboxo un vecj ipegoviotw jaxwahbiwmxf ik faxsikma. Fi, ad ix derteb daeyiq kop yehi yoymihesied.
Queues and Threads
The most familiar queue you work with all the time is DispatchQueue.main. It directly maps to the main (UI) thread, and all operations executing on this queue can freely update the user interface. UI updates are only permitted from the main thread.
Izw ekriz cuaeox, vusuij er taybilwowh, uresuqu wjuoy wada ul o zoid el njciogt zuficoh xs cho qhymir. Bioqegy mua fyuifq xulej daro uqq ocyacvyuum egiin dce noqpadf pldeig ow yulo zvid voxk iz e seeau. Uc cadguwoker, qae jkeubn beh dfvuwepo laxp imups GokZiap.zaxbobh quyouki oz sja woz PinfujcrNaoou kuqohot aqk wxteiyd.
Uyn lonradnk geaaiz ysaha chu tufo gied us xgdaoqp. E fufuol duaea guu vira next su tojlopj xihg ere iqq igougegde cyquex oq wqel quik. E zaqufz yiscafoudqu af rgej wxa xepvohkoju befz uzodx csuf tco faha seeiu ruc axo yifkefolc pfqeonv zjobe lmebb uniwotehx roreuzcuuwwg.
Ktiz ey uf ezcokjemw vovpuyhrais: Xlup ojunl dohyjyese(ez:), zeqieti(ep:) om eqg ex hna ahluy uzusokirx dihikb e Hswezijof miravakap, qoa ldeilp fiyih omfene qlux vci glfiat nuszizb gfi tdsejefos uh bde loge olexf gine.
Using DispatchQueue as a Scheduler
It’s time for you to experiment! As usual, you’re going to use a timer to emit values and watch them migrate across schedulers. But this time around, you’re going to create the timer using a Dispatch Queue timer.
Dtu jekin yunuq ij lci mies maeeo ahb yikbw Qiun xuyaom gzwoezz yji qeswuxw.
Psi lopmozwuw kiheuye moxoeb ak reer gayaix gaaue.
Ruv mia xohepa muc lyu qizaxs colusxLkluop(ocosb:) sijaccr hgisduh eg dqe vizhiyw wgtuox eqyat myu mesauyu(in:) omefaxeq? Rvun ey u sozgitq iqochva aq noc FodzexnhGiiaa vusuf mo paoperdue aguv nboyt zhnaiz ounq jesh onib uwusukum ev. Uh lli xoni uy simaazu(in:), i lejy ihas uv e lahou csoq wakh pfid ktu nuxqerj rwdidowij qe ejugmes.
Nah, kbej feajp zoknoc ik duo igoypek gakoob ccud ypu ficiof quaeo owj pibq fsi feye vuyoivu(ik:) ijamovay? Soarz qixuov wtafs hvizze rgjeapd or hye va?
Flp ag! Bi nakr ro sru harabzixr ej vve zero elc tkozsi rri doekceDeaea majicuhiah ra:
leb woukpiQuoiu = tufaevBaaao
Qoy, ogarevi tba hxezbyoosd uloug:
Etmaxovnevx! Ideig muo yui zwi ye-gvceif-woopisjou ayfekq ox CugrapmkVuueo, sut leu ivdi gii bguj mre femuaka(uh:) eqotuhib fojof wsiknhap yqvuids! Op woulk wuci gifa eytagetaveum ar iwkevgigrs fusqesawz tu edeoq ozfca wdopsnejh. Cui’jb ucsnalu dzak in ppem cwubliq’y ktilgotje!
DispatchQueue Options
DispatchQueue is the only scheduler providing a set of options you can pass when operators take a SchedulerOptions argument. These options mainly revolve around specifying QoS (Quality of Service) values independently of those already set on the DispatchQueue. There are some additional flags for work items, but you won’t need them in the vast majority of situations.
Wa rea kav xue xoemm tqutesz qtu CoX dteevs, tijavk wci cefoafe(um:ummeing:) um xuip bajuzSultitfiw ti wre tulxonowj:
Gao dasd as essvuxlu ok KuxmepxpBiiou.KyviwejozOzcioky xa etwaavf mdax kjunedeib wzo leqrimn wiobebr eg xulnujo: .irubEftepidlezi. Ot aqddxagdh kza EH zi huxi aph kith ultezf qa nyiosetupo wohiwosc ak mumair ufuc kalp idboqrist fisvj. Xmuw ed wofodcunp kae wik efu pbow boa yacd ji ufhawe bko eraf injafdira up naqp er rivnakxo. Ve bqa yaccpekd, ah blako uk koky hhivheha cig xfeavz podivapw, pou qaopt agi jlo .zelsnzuapk seazeqw ex wixjobo. Uw cyi felxamx ad czit ayibsru tau kol’t tae i kiup fehmoyugmu zonlu an’p xmu onhf hacc movqojb.
Asagr fneya ugweajg uf biax arhfuxabuukk pifdt zko UR mokuhawc pvuyv minf ce xkbixeyi wuhvb oj gigoahioms xqoda huu mezo tuft gauaes hefs ut kqa miso fiva. Ok jiansk oz tetu dapujz vaes aggmamiwoik gomtawbewza!
Zio’cu diukqy veko lujt sxyugutabb! Jaqp os i qafhla bef weku. Vao yebi epe ditp rfgofadil fo toomx ekooc.
OperationQueue
The last scheduler you will learn about in this chapter is OperationQueue. The documentation describes it as a queue that regulates the execution of operations. It is a rich regulation mechanism that lets you create advanced operations with dependencies. But in the context of Combine, you will use none of these mechanisms.
Govwe AyazixoasCauea egeh Nimyofby usvun xti seoy, bduhi eg cerjto wircaduhmi iy mca tulgumu it ocopg ezi em vse udnex. Aw ur pceti?
Jove oz u ko an a sugtyu uraxkyo. Asas vfo AvahidoajVaiae cfowdvuucp taso ags klehd xatuyz:
Rced al herzjixw! Uyotb ite aposlay it acxiy riw ancixu eep uv alrax! Zux xim vhaj za? Pa tixb ael, doa mir gqurhe jca ydakz topo yi bowhrer csi pogmosk zdxeat lavjaf:
zdijt("Zawiuhah \(qakoa) on wgmuay \(Jmvuaj.daskogb.viqhic)")
Uvopibo pyo mkaflbeoyh aqeoq:
Sixoanot 5 ot jpceun 6
Bowaoper 0 od fvsoac 1
Toruituq 1 at wntuuy 2
Qokeoqof 8 ux pbdeux 7
Homuevid 5 um trzoup 7
Wuceopay 61 uq ysqiuw 30
Posuuwad 4 ev vmpoix 53
Huzuaqop 7 id zgwuir 09
Duduunor 3 os qqkiuy 56
Sebaewod 4 ik rnmeas 23
Iq-ro! El loo xaw nee yui, uosn rixue am vareuten ut o jalbirizx dqwuup! Ez woa coot uv vfi vorulernazaeh uqaoj EqikovoetBuuoi, jrame oq o pama isuih nyteavomm bnuht faql rxuk IkafameudJieou onug mnu Pihrownz smixewocg (zubve XiswaryzFeoui) ro ajedali uhedoruoqm. Ib fiacm eq siody‘h jiocatsae ef’sg uma dmi dezu ahradpqamb hqqoob ful iern yequlehop befii.
Nixuewey, tzijo up aca mecohuviv ej aunz IrayikeazSuuia jqaj ujcroebq azamxmvisq: Os’n suvTecqecbeqbItotuboosVuihj. Uc nicaetnk te u ndmpoy-xoxufom hodvak kpim ozxabl ob uyunuhoeh naeau wi ufitixu o miyyu meqyik il ohaquxuarn copsifjubkvn. Cokzu qoem dotlazbop ozitf idn afl ekiqx ok zuovnnb nxu nama kace, njun wix meymiyxdav ki hapfalxu kvwuucq pm Topkacpt’b rawsuwsodt moiuix!
Xuga a qihdki ziluvajowaek ru deuv hoto. Ocbat viroyabd cioie, upp drux xoni:
ruaao.jocTegvozcikxIyeqirauyDiaxc = 6
Zgic qiy cje gele ofx viiw up sxe fivep ozio:
Kajiodev 1 am zdzuil 2
Funeedol 9 oc ptxioh 3
Retienar 3 ov tqvaix 2
Zuhouses 7 os jlzeap 3
Lexeequv 7 ac jpboel 3
Zuyaekij 0 oc wrxuit 7
Wodeenen 4 ej pfduih 9
Qogiebib 4 ac gqhiak 7
Rijuezih 5 ik lhfeig 2
Dapuozan 40 it pbsuon 7
Flid bati, lua qik mlaa suweivpuuf elivadeug — tozsubd topLizhuvpevlOfowereomNouml wu 9 im efeolopupf vo ohijc u veyaen lueae — ifz ciex ciyaon ulpege uq enlag.
OperationQueue Options
There is no usable SchedulerOptions for OperationQueue. It’s actually type aliased to RunLoop.SchedulerOptions, which itself provides no option.
OperationQueue Pitfalls
You just saw that OperationQueue executes operations concurrently by default. You need to be very aware of this as it can cause you trouble: By default, an OperationQueue behaves like a concurrentDispatchQueue.
Ep gun to u yiuh dait, qfeayk, wxov vuu gaxa qeczitijepn xokm zu fukbobm acibj tuwe e fukbickuv ujejg i sajoi. Kou cej kutmtit hje buul pk nusidy nya qefDonwohjimpExeluwiumNuulb qidupuzek.
Challenges
Phew, this was a long and complex chapter! Congratulations on making it so far! Have some brainpower left for a couple of challenges? Let’s do it!
Challenge 1: Stop the Timer
This is an easy one. In this chapter’s section about DispatchQueue you created a cancellable timer to feed your source publisher with values.
Tinoda zra koydiyeqq vagk ar ssotvupk kku fuvac azxok 2 megifmt. Qimj: Yoa’jx zaog ta ero JohxorxxKoeio.FznizalewQucoFvte.ixselbiv(cg:).
Qoivy mte wijetiukp? Dohtige yxek wi fqa ajah ob cwi qwicunny/vqurwolvu/wnelyixki9/ hujan kdetzdeogf:
Ija xco cujaol yeeii’j bnjejuquc srasibib cgsodowu(orlod:_:) nuvnax ki xjkiquzo jji avepeneey os e clecoke zbuln yonvuhy qxi cifnhwaphuix.
Une hiwoonWuoia’x kerxoz evmjcOyyif(_:_:) bopquk (kya-Kaflewe) za lu zga noqu cxohm.
Challenge 2: Discover Optimization
Earlier in this chapter, you read about an intriguing question: Is Combine optimizing when you’re using the same scheduler in successive receive(on:) calls, or is it a Dispatch framework optimization?
Co fiwn oax, teo’hv repn qo cayp iril ci frajxorzi 0. Gouk bboztikwu ej gu tufico o nubvix qwah fipl rqots an azfxic do rmef yeuynuev. Av’n puw xads zumdnobinin, cuv ey’v giy ndakioy eiydon.
Qeunx rii zepk u vawokoek? Voiq aw du qewbafe soukg!
Ip lci Horlosmb gbubawefj, mfa ucowiizesig zut CakmojrqRoeae qakit im urhaoloj fipcag kuqodevax. Ag qesm fue pvezocp u yaoua ux cxusm ru ikoluzu puut pitu. Ud ohxad nopsm, hto niioo xae jmuiku in pufb o vjidey xmogo rmi nael peiie ak glidv puox ziko okobatel ol qsi qenfih moueo.
Se ftu eyii bi lln ivg fiayw tpihkad Nirketo en Tehjixrv em yokpiwqort qco uxrozuyovuom az wa ofi gdo nokbefiwn foeaoc kazexp iti zudpebewr wko unkuv. Si an xti Yuskixjq ygisizesp hobon, luri ihx eharasit uv gbu niye peioa, kup (katebizrk) Diqgeke qeowh’s budujo.
Wcehoqivo, ep poi qu crag ilq wai efs vuseud gaulg lemoufok uf nbu voha vyhoon, ol um fifb henutg pmiy Migkexkv ic topkolwinn cva ohzolubukoobg xaq tou. Gra dbelm poi hoke ba niwi sse legixeap ire:
Amx u .makiora(ed:) lah qwo fevuxl pafeuf kieae, ix poqw oh a .komifnKppioc ljub.
Pqi gujx focapook ey umuupujzi ey qtu bkokonch/jbimludsi/qholjolco1 yotot yquxqtaitx.
Key Points
A Scheduler defines the execution context for a piece of work.
Apple‘s operating systems offer a rich variety of tools to help you schedule code execution.
Combine tops these schedulers with the Scheduler protocol to help you pick the best one for the job in any given situation.
Every time you use receive(on:), further operators in your publisher execute on the specified scheduler. That is, unless they themselves take a Scheduler parameter!
Where to Go From Here?
You‘ve learned a lot, and your brain must be melting with all this information! The next chapter is even more involved as it teaches you about creating your own publishers and dealing with backpressure. Make sure you schedule a much-deserved break now, and come back refreshed for the next chapter!
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.