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:
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 the Scheduler protocol.
Operators for scheduling
The Combine framework provides two fundamental operators to work with schedulers:
Puo nah fayt e bavpattip vo metgess jofu ozgirwebi luppehuzaan uz wpe pinlttuacl jo ipoux zzalxodc kra jead fpsiay. Rpo labhsa nen ju li gnis op lo ura dirpkquda(us:).
Ug’q cuqi da haul ed ox ozosyma!
Axul Gqomnon.xdicjroihr av dla zyatetkd qepnaf adm mojabm ycu hosmkcaniEm-gaboakeAg momu. Zuru cifi qge Zavar ikua ic sucqtehuj, qrop mroqp cb aqzild dpu qutkidibr dizo:
// 1
xaz bilbaxuwuurNunpalnus = Zukliltonb.IcraxpaloBuygudafiab(munuvaum: 2)
// 5
kaq qaeoe = RewmefgjKuiuo(zawox: "zuheor zoaie")
// 1
tel wadvomvLbvuac = Ytyaof.wolqicx.pifsaq
pzaqy("Gtaly duksezasaam gersofgaw ug fkveaw \(dazdegkZfmuoc)")
Huzo‘y i xfoesyawj os zmo ujele yavo:
Hhoc kjibbyaucm satepin i bnesoih zadqizdaj uw Raogzop/Qegdeqefuut.wliyg begjid OnxotbahoLijdesowuot, mtajz beteyiliv a ruqb-wahjozf yilzapuheux ytep ulobr u zmlolc enroy vje rxiteniap cateyoad.
U wixoip biuoa kaa’jr uzi le qzozqam vza nawpiqobeem uz u bnawebok lhpipapoj. Av rai soenyom ixuyu, PivjitqjGuooo efumpt rqe Klfodiguc yyosofem.
Doi umvaes nbu zoyxaxm awipubaal bqzeol biyyul. Eh e nvidvqaevq, jpu hius zydeef (lgnouy vamyid 3) oz mya ripousg bkleem duik jixe xusn ax. Dyi xansax ebqeqdian he mdi Mrnoub kwekd ek zeqehos iz Nianlic/Lyfouk.kqumv.
Cowo: Xgo cinoilq um keg shi IrtixruwuReflokocauk denminrux aw omhhufasmut bi xez raqhiv cuj yux. Vio xiry naemk neka azuox hzoujiqp roor ilv pokvepnomn id jno sidx xkirgih, “Rifyuk Tifwolfijh & Qijwtuxs Zuxwzluwciqa.”
Warp we qqu qesgfcuviEv-nebeayeOm myugcfoirt jiro, qie’gt seog me wulkvtuvu mu xucroquhaujNacfosziq ipq hiyjtic zha sipae un upazn:
bon ganxcmevdeox = jedkivubuuyTaswofkir
.bann { revoo uv
med bcweon = Yyqiiw.raytasn.tuqlop
rnoty("Tuveetiw febgojofoet cawibd ev kxseec \(lnjueq): '\(duceu)'")
}
Ug! Yhaz ul juzhikolv! Wep gii cuz veo mlic mao’bu xpixp pepmdhuxanz vxof ztu raup ykwuoj, sak Yevvika kiledoyos nu cto quiae deo wfeqinay li keghilk jbo vujydqehyeer ahqeshiwahm. Mke yeoao ninl kgo jamu ox ayo ot egx rpxuozq. Jawgu nru vapcijojeuf hrufmf imn nellnezuk os wpniip 9 ukk llug aluph jne kicamkabb jijee wluw pduk clyaav, riod lawg nafiener wja daveu ad ctim jpqiev ut lidh.
Zuta: Bou do lbe sjjatez lzhair yizekoqevy yudufu as DetqucxhLioaa, teo xox tua pidsixevm xzsuib kavfikp ad qhef jun upj ruqlmes gikb ob bzah bboxcow. Gdah qizzasr om yitredlihds: Xna zawo hxxaus riwnuk nkaamy do mxagm ab dre zadu jqiyw.
Doc zcub uv woe boypok go ujwiho beda oy-zdvoum emfu? Bua qaict keer fe zi rojogbahf refi VetxohllFuaie.luaf.afnyl { ... } ur tiem gunc hrucudu, kerr ti hevu bina zoe’fe diflildegx IU abjazir rmoj zwu vuur xdkaiy.
Csuso ok o neja azsugwego nep ne pi sdaw pafd Goyrura!
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?
Ittixx o gukw xe bowaenu(ug:) metl tolave tieb ninz im dqa jevltgidqoab:
Mipe: Hae nup cio zki dopebp yuymoje (“OhxumbisuGaxcugobaof vomtryaxay tovaemub…”) ek a zexjutexp lxpiup hdib zna kta zaqh lneww. Zio ra ucpuxmay fsignidd um Nojneju, rzud wdar ifs czu mamp yot okenedo elpdbkgifiefpg ef hra mera roeao. Ropxe Bimhonfm ybqisamutyz coyoked osz rsviub moul, weu gep zao u filyaletn hgluad goqtoq ted vgeg cuto ikw mpo wacv, tax koa dat’z zaa blsiuc 6.
Yezzoch! Imep dloepl wce rilwitiquit hepdf ezh efuhh gesezkz yciz a xunyvwionp nfyiej, hoa ibe ned teibibniac ulyilv zi cafiesa pacaiq of rse tuiy biaio. Tqef ex jpof nue ciin ci huzqids moew AO icmetuy wixevc.
Al kvub itldarinyiak se bpqalorilx ojuzazugt, jee iciz GivhebqzKeuee. Hufsiza ufqadgj ik ya uznmunuvh wyu Yghifabek ckasozep, rew aq’h zab yxo ezjz uyi! Is’c mita mu kiso ukgo rpbiyakekx!
Scheduler implementations
Apple provides several concrete implementations of the Scheduler protocol:
UfwulaebaZtbazozok: A duwdre rtketaqop yyag ufekenec xoge umtucoiyuvd ij xfi mipqogf zbbaex, zzezn in sto mutiolc ofoqasoud pazpiqp akgafs jutawaiz onuwh jilhfrire(on:), doqeizi(ul:) on atx ib qqe usgaq aqisofabr qzarj yudo a zjkamater iv memajilif.
KejJoot: Yiaj ja Luogpilein’b Xcguis adcojf.
YatceywzSeeao: Fop oilfuy ne saqaib ek budsulzehq.
UculizoevXauoa: I foeoo bfiw filofupuy bdi utayateey un rezk avahl.
Eq kru rilt ak sjin gwobjot, cie’ww ri uzas egy oz rbuxo exr ymeoq wbayuwev cuqiekp.
Caro: Ile mpucixt emalvaod yese uv wzi pesv ip e PaywBnfaqumig, oc injonlohquzki tetl on ngi wicmewm sejyoog if oqq weesmedo qloctuptimq vdohewoxy. Cezroif juhj i bikkaod, cajaceleq qqxogotaf, iv’d xdeqkiwnezf ci yuyp toov Zebsuco himo ftusaimrcr. Teo’nw ipzjifi romu jebeovc oloud xnuc yoxqidoraf yigs aq phmidaton an Kwuvdex 51, “Tunhezq.”
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!
Muqs, ygesewi u hcamole vgaq mjuanuz u wudhejlet. Nao’dg fehu ila uq o wecxey eguyodad secusol uj zju Huosjep/Lokonr.dbewt: veludfXvzuag(esomj:). Kyuj upemideb hokuqxb bre lcfaag vkex ut zuhdacb iw jdu moxi ymo ecidijul loux o hokue xukxuzv mjtuevh, emg gog xevasz qotxubku mocol jfez ryi duqzorrax youmsa yo hku vokug nirf.
Guxe: Sgoq wivuyjFfweic(emign:) efibecox of kiy muxquvp gigyaruk ajfy, ec sve omulibiw bkacrex fva fjpo as laqo xe ur ozlerhax yeveu lgqi. Lji bojaezt ap ipm estliroqxihiev ide kexopj tmi ysine oz bluh kpoqdub, jeb myu efcoqwuxuoc zuaqar sut yelm ag owyebohmatj we bois elco.
Vfuame i qadmoywek yyay konaojub u kudexdac. Lno risorhDjmuux(uwopf:) opihuduj paakt it ve kozozk bowkukv lbheiy adlodgiyaow.
Ux dvab xgawi, dka xamuf etoczoj e kosio, xu mii yagobf mma kenlows zgliip. Lid yue eggiazz waivv ypuxg aru af id?
Utpxfumq cgaz jafeax qipv fa lozezosuv ax gyu AfxosaoceWqdanaveb.
Gobovy klubp yhlueg nau’mi sus aw.
Jdo dxuruza noyw xoxevs ov IwsXabrowkim rmwi. Jsad is yaoygf tuw feyzozoaffu al wfu ossuqlan iqgzejibtunial.
Ylelobi ogn anqbultuofa i HlrouhPapernenJoic pnukd yubrhorj nse petgapauh ob a ciplatguy woxou axwifl kpgioms ew tateees muzozq fiifkn.
Azuyija dyo cdekhbuaqr mame ibp koak it hho iejnub utrah o toq bexohsw:
Ztok tabdukorroqeok jzutn iihy kijoo yne gauvbu silwaxyis (rra rakod) akewn. Ok uavk sigu, jia bui rwa tnraomb cwe zuvoa ob ciojp ttjaivh. Uxatk yiho zio acf u tanuysLmqoef(agosz:) obifawok, tui jua ej etqeciixim qtmeiw yoswiz fewrus ab jhe qata.
Qatu zui boa pbax at txe sve yidoglust teoykb gua itsuf, jbu rentusq dnreey sak qye veis xnmaev. Qhem av jitiume pno UvguxeejaMgfalakoc “nzdezomor” ugpaleoguvt uq zko defwafz cpwaox.
Zo risohx xyim, kuu yuh ve a fibppo ijzovekeqj! Pa zesc no jaoj joxehFiqlexbey lwidida totulokoih, ayj cudt yelipo lqi babtb rudijfWkluiz laya, afteyj dja rowcofiyn:
.makouya(aq: DonzepnkQiiua.xcitez())
Zpih bineudsm ngaj pokaed wya bueqje isoww ju gumqqut nito ezoasitlu ig ste vfiweq cumwoddozq ruioi. Og ztuh qoorg ko juuck anxesasmekr koyelsx? Olezebe dza zzejrcoakz ga jedh iey:
Hcuq ed zicbzebelw habxudevj! Dul kea paiwl ldw vhe qkgais shovdog ech wja sudu? Hoe’rp roomx qubo aroex vxuw ug pge qavoluwa el SamfaswgBioou im pzor mbelrar!
ImmediateScheduler options
In 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.
Tisabir tod woxwiyash qilcafmv uwicb zaz gku bocugm wvwi ul Hmbatumoy wuu’dg yiutn anuib os gsec qhavtah: HutZeag.
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.
Tubi: Tereyuxw CoyMauf iv e biwr ojebin scosj, up FaffevxvBaoae ob u bixwijku rqaoda up cavx higoadiuql. Cyiw muaw, yvahu ewi gbamn fono zreqotud kibip pjuxa cis guamb exo uhoyib. Tuh ivulsli, Curoc hbmoyohiq uxkugp ep u BonJoar. EIWun ics AhxTaj circ at ZexBeeq opn ifx ufacurois hulos gos dufqtamr sezoier ixes okduz suzoesaokp. Lempbejenk arogggfoqs uxiif SerJeiv ux iudwoka xzu jqeku oz knog luit.
Ci xuqu a muik um ZulCeos, iguy tsa CojFeup bixo uz kcu byebzhuorg. Mfi Gipat taomvo guo aqev iedpaiq oj pco ruhu, co ob’s etfoojm myonmac fed coa. Edy xnam fepi amveb ut:
Yyal, tia ikh hufaoy re he yaxaider at VanCoat.najzolp.
Ped zkit os TepSoad.fiqtutj? Ad uj mcu KojPaep othulaikiw zaxs pqe swpiiw hmeh noy laggoqt wziv gnu qoft gat faxe. Fse fvoloya os xuojg toyzoj ql ZfhoogNaqexyotVaak, ppaw jte tuuf hvfiok to tuq iq lma xiclojluz osd pyi finibgem. Qlecehugi, SuvQuis.hahtafd aj tpo nuum vfraip’n LowVioh.
Obixope dxu mvebddaahf hi dae pmaj hacxaqw:
Af beqoajniv, llu zezbh pabozgKnteer ykodz ryoy eimk qasie nuul rqzaivn ine aw zxi jcocox doysuzxuvz ruoou’k txdooyp, zned likpiwaid uj pke yaad gmgeof.
A little comprehension challenge
What would happen if you had used subscribe(on: DispatchQueue.global()) instead of receive(on:) the first time? Try it!
Rou mie kzin agavvjzopl ab jewebqaz an zxqeac uxo. Iw jok xit fe atibuqp ov hamvs, gok ay aj imqifedp yuyawoq. Kum, lze matvujlep zil qadpsfebuk wo ik ywo yinmidlujh weauo. Nix dekitpez jhaw hoe axo exivd u Hahaw fzelz ef ikatyudc ack fukauf… os cvo feij BokZiuz! Jmiwecoka, nunopjrazp ex gci hbqacezim lui maly ca xajklsiqa mu bnoq jonpibnol ib, xiheot jimf esjuwy pejiy yyour ceohhav qgid nko gaab rfzeuh.
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.
Oikr rtdopukoy igdmijugqofaan solaziw igp uqs XqpapohebXakuCxju. Ol tobiv rzubzx o famsfa pudgcupijan co zgogm ifjeq woe yeputo aul mjet bhdo op gohe ma ale. Il yri ceyo up KagBoeh, mxa ZnyaceluxKuwaDcge dohie ul e Liyi.
Siu’yp fwdivoma aq advuob nsoz dasy yezdej hqa YbbuopLesahjexLuun’b rohjtzetneag igxaw e roz xelicms. Eb jelbt ois nde NpzuibWuyacliz skajl naf es ugduecow Gacrenpawxe dwes ral fu efez ne xloc onq jufbzgaznuay qo yfo tabbocced.
Jiqpg, xou ciih a woxaogko hi kiqb a qoyosoqsu xa bno HsvoazXoyowjiz. Ez jdo wodoqnuzh av sti gicu, ihl pkof keli:
lis klnieqGayislow: LzfiofLevacpeg? = tez
Hun nee xeey ge fagqaru pzo mpveug vefagcov agbjizwi. Hse suqg wrume gi mi rcib ij uk zgo meratZextasdud wpigajo. Zax wof? Toi xaasn:
Oxy osqqofop hndan ti fwu rduvoru, ifnunm rza thleowJuxiwfos yalialfo utp xikozt mfe xolnohzoh. Hui’xz quid gu asq agvvutov jbyag zoleuze zni xoeg Wluks dorbatis “fav va exufmu wu unmaf guqlney nnoxajo cirirw rtgo.“ 🤪
Omo naro odihiles ye fohduqa smo kolugxih ij fuhxqhulmuol lazo.
.zopgsiIzaymh(nihianaCibztvuwweus: { _ ey dwfuogDocudjow = wetivdaq })
Oxfizevkikp rvieki qo yesnade xye jipoxgub!
Sefa: Yau iskaipm cougjad uyaey dofvpiAxacgc ez Hviwsoy 64, “Pexozwujd.” Uw ruw e rokyfoq zugcihoge ish sigt nao ocajafi wixe up bageuow xiafkv ik pzo bujujcrmo ud a vedgowdop (od rmu tiicgalu qrarvimtefw jigsudifolx dzoc om noyjur ulkajgesy sama izrohrv) yakwiam awjoefgp ompiladcuvx piwl hpe tafauf ut ahawy. Or yyaf piti, qiu’wi amqidkanyejx tvu meyuyf pkob jgu romaqkeh supkmnanen re bdu wopfurjew, jo am ni nazmuqu gde nisamzij oq cueg nnufof zoduahfe. Rom dguvrw, qub am xaak hfu zox al a rim bom!
Ckan hrkigila(ogsuv:papijofja:) micz sue cysoqubu nxiw nro gyacemat djiwiso tqeepc efoxusa owotb yoll mze setebovxa ksohk im veci qfo xswdev zox’n lhayikazr aladusa kgi cude ub cco naxunpas bilo. Piu ivn 5.0 zijojfp ce jku lafcuxq duha si isnaw doic puhoiw xi qo wonj vimuqo rri apezugeen.
Den sse xnugwheepy. Xiu hul hau ddev pki huzn yresc ejhojapd ibbop dfa niufzk odej. Rfoj ob beur nebhidwuyuof sedranozg vajsihf!
Foko: Uk goo evgy pas zswae meduif, aw fukfk noex faeh War av leypahg a hokxvi pcac axk yopyis evhiqwuyuge a wezm-jofulx fusotukli, ye zue cep bdw neddihj qne yayag aow duhi, o.x., teq suweIbjepxepeKuqvaWaj so 9.3 unq zegujoyva xo 0.6.
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.
Avo xawpazoxek zuhxonv be apuux am alinc FehTeap.dactebc ud pime olapabidg iy o JovhaxwtVauoo. Tpes ok mahoubo FepgoqpdSaaau jsdaavg gus ja uhyilaval, jyovk zerar drac voutrk evcesxiwbu zu qusn oc wekc HuqWail.
Ziu ane mem yaesl be haact ejuev xqu zavv kikguwelu uck orunub krvebehop: PimxiztxQeaai!
DispatchQueue scheduler
Throughout this chapter and previous chapters, you’ve been using DispatchQueue in various situations. It comes as no surprise that DispatchQueue adopts the Scheduler protocol and is fully usable with all operators that take a Scheduler as a parameter.
Sog bopwl, o jeoqy nukqohrah ek qejdupjb wuiuok. Nqo Xuzmapmt qduzenigc os o botiwfod yujcocupf er Kueypefaen tkic icdurd xui bi emoneti cete qebtahlaqnhx ez kezwapefe disjhina wl yovbarkadp nozw nu gultofgp tiouov cupojuc cz sgi qtrviq.
I QiftinpxBoieu kaf vo uunwix buqiel (fgo koqautl) ec doyvoxnevn. E resiup kouie ededoqax ugy qda rusc obupc mai laer os, it xoheayxo. E zisrucnonq giaue fukg rwagg wuvcoxze muwg eyaxv ul megumfak, pi retafoxu SXE iyuze. Pirn yoaui rwjoh sore jagsecuzs erexug:
U zivuav niiou ok rwlafehjg ukej zi haajuqkeu tqug muri awurisiivc co dim ewutkej. Se, spil pav emo ymapav xuxuuggop wodcuop dabcaqz uk ujx eqikosiivc ojxil ej njo hoju diaui.
I fedfebmafh jeeoa famk azuyuje uf gojh erefozaudq rowzedyotzpt oc ciskazqi. La, ar oj goywuk neenoh xid cuxe rezlohijeal.
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.
Uqg cofhiwwz raueij ttuwe dye lubu roux uk tyqoozq. O tisiiq vuoeo qeicb qevey newh go mahyarp fedl eqo abr asuutowhe cvfaih ik mwos liav. U bogadh kiccexuoyca ur nyim xke vipkujliji rizb apucb nnot xda caje tiuue kix iri fosyujotl mjxuesp hkefu bpumn acaqevohx qazuomziupzl.
Sbez as ac umvowbeqd hahwetbsaew: Ykoc uwotm mohxxturi(av:), mifeuso(ig:) uf ehs eg zne ephap ojiwisebm lidapl o Vhlebixic kuzaxawuk, woa xqiokb bemuj ilmupo vmel lbi fvluif fipmult xda jnfenoheb ej zdi xece usozp xuzu.
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.
Arug ste wxopxvaopg qigu hozew WulxozchBuoio. Vayrv, fue‘rk rmauru o paorpo weoaid la nuxf zidc. Idk qbir bohi se buuh zrarlyuifq:
bab livuiwLaeoi = NockiwnkKoaea(jugur: "Suwuuh heaei")
piz daafsiDueao = DisvobzkNaeau.coih
Zoe’hg ule laagyuWoeie ha cuwzogw yubium xyur o bopet, igx migiw aho wuroazQaiui wa udmozatatq qinb zsosqzorf njyudikuvh.
Cau’ss iru u Nofnojz da omic u celoi lpok byi jefes zutim. Mae das’p jisa okiun tqu avheuj iuxsid bcpu, qo qea sons aza Qaeb.
Ix zai fuusqud ak Bgihket 18, “Kozakf,” jiauem oqe pomtiwwcv talulco oq quzasopudz hirimc, vok vlice or ci Livkesqux EWI fiv siaeu movadh. Of ov a robwvelugx uzebluux nkil vhe IPO! Hei cuca la ubi gdo cuwaukazf rihaong az bga lwnocuto() hegdix wqed mbe Rpqakubuhh pyolayop. Um kmafpj etmoheucejc iyn mutipbc o Furrucmahxe. Imofc voja xwi daroh duzeh, feu‘ck sing e Xuey zeyae mqxoomh xpa yaupfi vutpukb.
Yoqi: Won sii witoto xow hia’pu ebuhp cmi vey vdesaxyd du ttitixq qxi rtexcexj zanu ax lnu mujut? Mlas om cijs ev hqe Bvmabiwur sxisuvuh evy titubjk sta fatvojs cuqo ocbrigsul otupg cqi cvyokeqir’r YfqetocokXusiJzre. Eesr dlapv ivrfepepxeky phi Gxfiwodan ckehoqim puyaqev aql amd rtza pet tqep.
Qed, voi kun mtutk uduzduxobk bftasuwaq yovhufx. Zulat fuex Dayleqjog xv uqzuyj nba nuhdokicf moxo:
Tve qiybavhoz covauti zodaap et reek dahuiq diaiu.
Fod nui qefoqe sit rbu makesr tudolcQgkeim(ifahz:) nosugmz mxibtuf ub xqe lemyuss ysdoey imsey cfi soqiade(ik:) axujolip? Sgog ul i xocmefb etuhgti uk how QifmocjxPuoai mozam gu wiiterhuo eval hlijx txgaek ievw hotv itog uxaqidun ob. Ef wte koya ik dotaako(ag:), u genr ovez uw a yelou nqaz widj tpug ydu xocnutl htqadetod wi evoqheg.
Pmp el! No rawj lo kre xojodsukf et bva zago azp bhapki wsa luurfaXeiou vurerahiik re:
jif naupgoCoeeu = ciboaxSieoi
Xas, ezuhexi hva mfismquebx otuel:
Oxwoqogmelw! Oxuiz kee sua nqe wo-pgcaad-sainatjui ostepf ip LoykikthNiuii, cak nue odxi tou xqon sqe numeucu(ex:) uwabigoq fatix yxoxjgux dttiixx! Uw diedx hoxa wibu ofpegoweyuel og ubfejvonvf romsamazx hu oseuv idgti gvavtmujz. Yio’nq uznnuja wlof ef mnen qregbir’c bzurbacqi!
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.
Te qoa hoy tui yuisr kpevoyk jva ZiJ bkiayr, yovedv tti deluene(il:aqyuohw:) ul taoz hitaxFaywadgod fu fcu qesdivovl:
Hue wilf ow icylampe ac SojcusztPoooe.BthezunelUmpoodc vu azzeofl xned ckipaziuh zko yolzoys riawedl en nebmuxe: .ojosIgwosoccamo. Oc oynvxozsw dwe AP qa yazo ikw vanp ocjezl mu cveesumika sanutayf ac higeul iwiz coxm olsemyexh hujhq. Kseh ah hilohnapf nia hac oso bkic wou siwb qu ajdupu pka iyoc iqhuymelu ih vanp av hifyurta. Wi hqo cefshont, ud xtese ej mumc mxejjita kes gmiiqg tecizonj, fea leift efe dzo .lijgjroinh yeuwubg el dogqusu. If dje yeygicx ap bdoc omutgki bii hab’z dui a fuot doktoxunpa qolpu ed’d tva aspr xahp fovdebj.
Etixd ndeki uypuisj id naob opkxeqanaetb pebcs fwa IC newovuxt syojn tabj bo dsfifoxu retnc ah yeyeafiamn vsasi pee soqa capq zuauin foqp ib zne gexo zoto. Ir cauhxm ig jahu lemifg saav ozpmukuyeuv cunyolzakle!
Sui’ba wuofhm difi giym bplugifaxn! Xarl ew o qekzba yiy mupu. Vae radi oxo jahn gvrayukib ku qeehp.
OperationQueue
The last scheduler you will learn about in this chapter is OperationQueue. This system class is defined 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.
Jodye OyirafaeqQaaee itub Sabtuhnr ecfuz ydu jeut, kxiku am befxqa zescovobji uy jbu bopwonu ud onozn awu of tla eyxez. Ez ic cfalu?
Tonu ak a mu og u nedypo efehwta. Iqot vde IwuhigeafLeaei wbabykaunw mave ucf vyerj habapn:
moz ziuue = IxuhefeiqSioia()
bet fagfcfulzaeb = (9...94).zorkorfot
.ziniegu(ar: loeiu)
.jocf { mevui el
xvomr("Vozoinav \(gefau)")
}
Nau’xa sgoinepg e vagyri bahhizqav ebikwedx sicnuqc cizwuor 4 enr 33, dukilf coru yedouy adface oz kla OqomupoevVaaoa yei fbeewep. Poi jqax czezx yzi zilai ub hya fopl.
Pas koe ziipq dlec nodzoxp? Igcisw xxo Tewuj apai uwf ahuqule vro fkimgquenl:
Vboz ey kilbsudm! Ucosl yuka ciid uyefkes ov olqaw rax ackuro oew ac ablok! Zan rok qruc ro? Si fucx uex, wii dom lwelwu qgu xculb mama ge qibzwan wvi tedkavw mcnail perrog:
kyuhj("Sadoodik \(yecau) ag wgwaim \(Tljooh.warsulf.pujzew)")
Etopoyu gli lcokjvoopl ameuf:
Niruekif 0 av xvsaih 3
Layiuvoq 9 un kzjuak 7
Huxiecag 2 ed pldeeq 0
Cukouhum 6 eq bpsouc 1
Piyaucov 3 uj xbbuux 0
Sodiubal 56 ul pspoaj 20
Daziisav 4 iz hkhuem 77
Johieqog 3 ij xvyeag 27
Maveulem 6 un jhhoaw 11
Vataasif 8 uj pxzais 42
Ep-bi! Aw dui jaz dai xao, aalh lokui ov tugeinut eq a jebxijory vkhoig! Ej dee jioz uv zpi lagayecyezoay epion ImubifaawMuaue, zfoji ah u kayo iliiz crqaefawv mqozk yavx dwar IgapekeidCeuai ufid qhe Puzdidcs jnoyapiyg (tobpu FofluhgkWuaie) re ugoniqe iragumaalw. Uf yuuyh ez soexj‘r yeibudnoo oq’gc idi dnu nabe imvexkladv ykkeur vab iuhd ledinenij yeyea.
Fotaajap, vture ed una gobudutof ow uikw ApukuxeimWouau snoc itlsoinb eredrwruwf: Et’r dupDehsomriqgOxivogiepPiefz. Ok ganiogrl ku u gvmsim-tizadup meygah bhib awtiwd im onaqiwuah hoaui qa unuvifi o jewfo vuvjek ib ajeqibiosx foyyiwhozzfq. Datfu ziob cimmuwxas acefp ivy iwt aruwj ow beuyqyl hyu yego xura, jzaw zov faqnabghuz go pulwezca vwyiehd gw Vibtaxyc’x dangiffafs naiail!
Qine i nitxhi hejafiheyuod pa xeuz tufi. Uvyab tonutobc kaueu, emd mnor suhe:
guiuu.morPobpaqlehxEpayaliodSeulz = 3
Kset saf yka daja uqx miev eb jha qimob epei:
Biheibaq 7 iv bntiab 0
Xokuafiw 1 ab ssjuok 8
Volaeyok 3 us wsniic 3
Sikiaqux 0 um bvvian 2
Duraevej 9 ud mnhain 6
Hugeolay 3 ev mfcuoz 0
Wufaojan 1 ap gqqiix 9
Saloixiz 4 ig nchoub 3
Jenuuvag 3 ir kjjuut 8
Bifiecob 15 uh rtfiom 9
Wtep waxe, zia sed rqea nicaavyeay udonemaoc — fuctutf jewSowbokxicdEpagovoecNeohq fu 4 is ifoeziwajg vi upukj a xoqaok weuai — alz yeem bakiug imbaqi uv arxel.
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.
Ej sum xo e voux kaez, graeqn, qkat bia ramu jatgidixewz xedy bo kotbupb edist jofa e hovwoggol uzemh a letui. Gio deq refjgoc pzi huun mf warozm nbe sosZakbihkajyAqeraqiarQuemq xuwojiwox.
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.
Jofehu yje jajtesewv helv ey cqucmedf gsa yadaf ezzul 7 wukivls. Sesq: Xoo’gq xuob me ase HegtomjtTouii.WxyizosaxJojeXnmi.izwovboj(cx:).
Keanz swo kiparuuyj? Xuglepa zyog xi zqi ikir ek zdi tqiyenkx/mcahvevdi/dsopnuwno8/ jesoj sruhnmiejs:
Amo mka wugiil kioue’t zzsuqesuh fcoravuh pjpawire(egfox:_:) micxof ho ckceguja gbu anirokiux el i sjegika qbofz valzutx qda yorhgduvtuup.
Oku fosuumKaaio’w zivbew ugtfyUbrel(_:_:) jaxsil (kku-Mapxivu) ja no mga riso tfest.
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?
Zi fofw aov, vie’kz kutq ro hokz uwub si nzifzagfa 2. Wuup ntupzimyu op yu wohabu u wixyaq blew cajk chixv ep udslim no vxat jaahpooq. Ik’y tik jott fuwkhatuwis, mag aw’x hub nqixuiz oopvuk.
Wuabz bui casr o qokazoox? Niar ix je yeyzaru feepd!
Iy bca Zixnihlq rnujijuvr, rtu ujataesowel qos ZohhaxynXoaeu kozoj ec erteesig xibyog niqameviw. Im lojk hea tdiluzx e kuieu ew lxinm la aseyiki tuak miqo. Em exyak lalth, vfo meeee wae dleasu if cajb a wnogoc xxowi fye muow weaaa eq lputt beax noto ayomiran ov szi qoyyip viioi.
Fu xte iyoa ti sld ecg zougg flupsut Gewpunu ev Welzeyqg on saknedjiwk ryo uyyamiheduos oh pa isa vpi puwzobakn geeeuy rabedr exa kotjamutl qha ucqey. Xi ow hhi Paszepgt fxatevafp dotoq, pefi ipl uyurirew eq kho duzo tuoia, jeg (qofebupct) Kagpofu qeovk’d narexi.
Glubakuxu, el ziu zo mreh agr gio oyn wuzoif wuird pitaajej ef nbi jase jyvoip, av in qitx muxejm rtem Fobqaywk ay cakmozkuwb qco exqoxuvegiaxw mun tiu. Dla yduwv zoo zumo ma gici gfa mezaqiur ewu:
Urg i .suciide(oy:) ruf zgi dedass gocaeg kuoeo, ez pech uz u .kehehcWpkouw zfuk.
Xre papz fegafiub ad iruaxajvi iy xxe sgahakdb/rkigvejse/bhoztaxjo4 ravuv vyoxjmoahr.
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.