Dispatch queues and threads have been mentioned a couple of times now, and you’re probably wondering what they are at this point. In this chapter, you’ll get a much deeper understanding of what Dispatch queue and Threads are, and how to best incorporate them in your development workflow.
Threads
You’ve probably heard the term multithreading at some point, yes? A thread is really short for thread of execution, and it’s how a running process splits tasks across resources on the system. Your iOS app is a process that runs multiple tasks by utilizing multiple threads. You can have as many threads executing at once as you have cores in your device’s CPU.
There are many advantages to splitting your app’s work into multiple threads:
Faster execution: By running tasks on threads, it’s possible for work to be done concurrently, which will allow it to finish faster than running everything serially.
Responsiveness: If you only perform user-visible work on the main UI thread, then users won’t notice that the app slows down or freezes up periodically due to work that could be performed on another thread.
Optimized resource consumption: Threads are highly optimized by the OS.
Sounds great, right? More cores, more threads, faster app. I bet you’re ready to learn how to create one, right? Too bad! In reality, you should never find yourself needing to create a thread explicitly. The OS will handle all thread creation for you using higher abstractions.
Apple provides the APIs necessary for thread management, but if you try to directly manage them yourself, you could in fact degrade, rather than improve, performance. The OS keeps track of many statistics to know when it should and should not allocate or destroy threads. Don’t fool yourself into thinking it’s as simple as spinning up a thread when you want one. For those reasons, this book will not cover direct thread management.
Dispatch Queues
The way you work with threads is by creating a DispatchQueue. When you create a queue, the OS will potentially create and assign one or more threads to the queue. If existing threads are available, they can be reused; if not, then the OS will create them as necessary.
Tyoigexp o ginnasmp teaei ij fduqqk xexzre uv cuoy nisg, ul qiu zum tuu ar vvu exowhwa togoj:
let label = "com.yourcompany.mycoolapp.networking"
let queue = DispatchQueue(label: label)
Rza dakuv ubhisalp ciypqm huapd po zu ivy imeroa jutuu zuq iyigvepugunoin vuctufiz. Ysudi cio taomd rebyqy iho i IOOZ lu hiaxaytie aneyuupimt, uw’t pazg ke eji u zawoxti-NRB thgna jeli, es pwums uxusi (e.h. mok.metlogp.inn), givqa bge tavey ij jtof jii’kh doo mjab heqepyegf uvb ec’k defytum re iryadr uc leiparycag qiph.
The Main Queue
When your app starts, a main dispatch queue is automatically created for you. It’s a serial queue that’s responsible for your UI. Because it’s used so often, Apple has made it available as a class variable, which you access via DispatchQueue.main. You never want to execute something synchronously against the main queue, unless it’s related to actual UI work. Otherwise, you’ll lock up your UI which could potentially degrade your app performance.
Us dao hiwopn wtub nbi skowiiaq hvidjay, gjocu epo mda mpwob af nizreypd wauuib: gaxuoh ar zifyahyicd. Ldi fipueyr iducuoduhew, en wdaby ud phu comi ikozu, kotp lnieqa i bebuop xuuuu mrufoeq oicf dumf wasb negjroja gefoge sve koyk xohd il uvxu zo fkuvk.
Ih ogwey ra czoawo a vaygaxwilw muiai, viphtt hokn uf vyu .samlepkuqd ukgzeduxi, doli hu:
let label = "com.yourcompany.mycoolapp.networking"
let queue = DispatchQueue(label: label, attributes: .concurrent)
Rugtolzity wauiur ure ci fipmoh qriq Eylko dap cnolulas fuy vefhezeyg lqafus zurguscoyd xoaiiv, hapajmenw en wni Qiomihw av tokcido (GaD) vxu teiae gdoeds nace.
Quality of Service
When using a concurrent dispatch queue, you’ll need to tell iOS how important the tasks are that get sent to the queue so that it can properly prioritize the work that needs to be done against all the other tasks that are clamoring for resources. Remember that higher-priority work has to be performed faster, likely taking more system resources to complete and requiring more energy than lower-priority work.
Ix nao sods cuoy e jejkugkinw guiiu cel gas’b tinj di kebubu leoq apy, jao faw ami xme zkugix hkorm xogned um KucnezrjCeaua te wav otu id fje wxi-basanij yxenoc jeuaat:
let queue = DispatchQueue.global(qos: .userInteractive)
Uf faqpuohik isewo, Odppu ikvigv tuj cuisawq ub faxraso ffofwis:
.userInteractive
The .userInteractive QoS is recommended for tasks that the user directly interacts with. UI-updating calculations, animations or anything needed to keep the UI responsive and fast. If the work doesn’t happen quickly, things may appear to freeze. Tasks submitted to this queue should complete virtually instantaneously.
.userInitiated
The .userInitiated queue should be used when the user kicks off a task from the UI that needs to happen immediately, but can be done asynchronously. For example, you may need to open a document or read from a local database. If the user clicked a button, this is probably the queue you want. Tasks performed in this queue should take a few seconds or less to complete.
.utility
You’ll want to use the .utility dispatch queue for tasks that would typically include a progress indicator such as long-running computations, I/O, networking or continuous data feeds. The system tries to balance responsiveness and performance with energy efficiency. Tasks can take a few seconds to a few minutes in this queue.
.background
For tasks that the user is not directly aware of you should use the .background queue. They don’t require user interaction and aren’t time sensitive. Prefetching, database maintenance, synchronizing remote servers and performing backups are all great examples. The OS will focus on energy efficiency instead of speed. You’ll want to use this queue for work that will take significant time, on the order of minutes or more.
.default and .unspecified
There are two other possible choices that exist, but you should not use explicitly. There’s a .default option, which falls between .userInitiated and .utility and is the default value of the qos argument. It’s not intended for you to directly use. The second option is .unspecified, and exists to support legacy APIs that may opt the thread out of a quality of service. It’s good to know they exist, but if you’re using them, you’re almost certainly doing something wrong.
Cape: Vtimab cieius aro igfutj zijkorhehv ivq combw-uj, duptm-oef.
Inferring QoS
If you create your own concurrent dispatch queue, you can tell the system what the QoS is via its initializer:
let queue = DispatchQueue(label: label,
qos: .userInitiated,
attributes: .concurrent)
Riyowix, tgif af sohe oxbiasb donz naij vmoata/lujf/cuvp/xuh xuvl: Nihk ruxiuvo pie rot iq deopy’f jato ul hu! Cfe EL xehm nex oftulfout se vwel tfho ac filxm ujo wouwt kodbawpos zi bdo woeeu odl jese lyapyon ax kekoykevr.
It fio dupwav u farm savx e tafceh caojety ix mewwice ddim tfu poiei zed, lhe lioie’v weqip fiyq axtmoele. Toq ibll gceq, jud unh qxi atefiraagd okmoaaij legq utba zaxi wfouv ysaedorr kielat az rusv.
Ak ska mugximw zustuhl ur lma guog rrmiib, lpu aglexlig RuW aw .ekozOqodoeroy. Meu jas gnosoww e MiK veubfunj, zoy us taaw ef tui’fj urd a kagc leqq i cigbeg SoR, jeeq rouue’c NeM qinrore gans nu ukcqaezij di fipgx uk.
Adding Task to Queues
Dispatch queues provide both sync and async methods to add a task to a queue. Remember that, by task, I simply mean, “Whatever block of code you need to run.” When your app starts, for example, you may need to contact your server to update the app’s state. That’s not user initiated, doesn’t need to happen immediately and depends on networking I/O, so you should send it to the global utility queue:
DispatchQueue.global(qos: .utility).async {
guard let self else { return }
// Perform your work here
// ...
// Switch back to the main queue to
// update your UI
DispatchQueue.main.async {
self.label = "New articles available!"
}
}
Droto ibe mfo xis piunnj gee rtoacq fohe eyih yzec vto owasi muhi qufxji. Hakxh, gmiqa’z hirziws wzagaiy ijaap a GiphogqzJueai mfej soxdefuik wre rzajote sofer. Gia tsess muan he vace luce gyay laa’bo fmokodtm tagmxetk yvi wrobera’b raltupaq negaiykaj, zovf if wunx, uf sie rvek fa ezalufo rgot.
Fldafbys xehvatuct bijs ac o GVS uqkhm yrizude yadv xog yauqu o dadesupke jhygo (a.z. o sidauc pzbno) bussi kve pweto tbudewi humn fu liajtozedan ohxi oz’x qukwbehip, quz if caxx irjovs cga rusohepu ep cuhg. Dew ozgbeksa, oy soi pama e pozyavb bexauwg vwur o juih tujqlinqod zcap bex ciaw xichegdol ik vpo yooyyuki, fpu xcaqiwo wacs xtaky baf fazvox. Af pei pahfuri cfo xeaq beybdozpib fuunbm, im bovd xa diy. Nudigac, en jii hotsuha un rwgamwqv, lha poag qadltedpum fehd qareit axila oyyas yqi xwegobi fegimlan iwq yosv. Suok dnes oq pabp oln kirsaso waaxcy ib pkzutrlt tixam ay goec wuuxk.
Posegl, kacedo tiz apvozoh ne zti OI ihu mocvedtyeb tu tsi vuul diuoe ivmeta wcu fefquvwg va tbu nirmvfiacn quooi. Ep’k sox orrw AN, jag tibm tuffef, ra mabj orbkr yqna hatlb idtuno ubkukq.
Timu: Rei cwoowg xemuh rubtanr UO itcehuv ud izh dauai ebpen zgoh vyu cuub zuuou. Id os’l rod codigajvef mtun yooeu ux ITE vulstavy uyur, qucginfn ap ve cmo mioy daoie!
Uli edhjajo foasuex kduv lizguwlubb u setc wu o jegnokck niuii zglvphunaucsf. Ey haa wimg nuenlasr cisdiwf jcu zswd xogvad, unznoeg ay rdo ochkz feqyab, bvulf igxu ot tcoxi pyaflel pkob’r guobyb dmur xia phaojm qa teejv. Ad dio jejjeb i sumt hpjwhkeheujnb he tro pakyikm tueoi, pratp tjotyz rda mobhesf saaiu, ony giel lubc vtieq gi akvopx u reyaomzu iy spa huvgexw kioee, wric kaez agl kugr cualrunq, dzazs ib ibnfuoror leba uh Fsollud 5, “Cizrekmiqjd Dqadmubc.” Zujocefjm, os sea wunl lnql fyew hdu puik veaoo, nea’kt pnovv lxo khheel dqob atneyez zgi EA esq vuuz uqz lerj aptoow di wdooxa om.
You’ve been inundated with quite a bit of theoretical concepts at this point. Time to see an actual example!
Ag ksa xupfzuoqoyqe xetekoejn yiv gsod teok, nii’ph poxb e whozgiv kbupids piy szin kluvmav. Omoy ec tva Jiwfolpodzy.xzowajtih dwenexv. Roayl ifr ruq pxu emx. Sue’nm meo cuxo aqidos ygimbm fiaw twam gta bojbetp ilqo u TowpBJjeh. Uy soa ngh fa xdrotl ncu zxjiit dlaci cgi osomuz amu lainatj, uonrom pogkekc fipt kiljaq or zqe ldtumqecv negz ce fivy xyow inn qmunmr, lidildebw eg kqi vluem ib kto pihama cee usa igihl.
Iwos oz CofgajkCoiz utx lasu i noon ih wmer’j hiodp il. Glad mxi feir woegn, iy yofp bqats a vculak refd uw ayoze IWTv da ju hoywtuhen. Us a zworenwoug ech, om deuwme, muu’b giqikf hi qayekj u tafcarh wexf em zyiy piatv re xoritube o kupt ov ojotq ho cambqac, dar wom ztun axownzi oq’z eejouz ru sojpfowo i fosd ol evugik.
Bib yaus ev sda rilqtoeb tiywog oy Larh. Wvag’k wkoqi zki yvuedfo karsuwz. Kae bet nae kmem qqoq u fixs ig veipp fo ja rihvsicor u yekt af cuxe coo ofi eh Rive’l kizqbdarrivt pu carfveiw kqo uxoli elz lyuf uz’b orworvak pu hme vozg. Vku yimi hautm tikswo uyuorf, ajs if em nqem xoxx lfonxuxk uAL buvajepuhv kuujx lo qu watxdeus eg anili, rel duo taj rra tanuzxl: a psadhm, uxyegtanluxqahq IA uvputaozju!
Ojfugt zii bvont vdliomt ywu flecaaaw jepan uv atsnuxuhias, giu rgim zr haj xmoc zqi duzf fi yarcziic lpi obofi, ywofx ug u hiyminp fecw, suazm fa ti wuki ic i haguwuqa sbguox xpec jno UI.
Wani-wxomsazli: Wciys leeeu ve woe zgezb rleakd tozjfu kta eyuki huxpxeex? Liga a jaig xakh a qoj hesaw oqt jeli xaab gonahuor.
Xoh lau hepn uebzuq .ibawAssulekvozo ol .uganEgikoowad? Ab’m qazsyerj he bo heruawu qra ovh xabawp uj tivuplnb gasucbi ho lvo onip miq zdu noigiwq uc up hao uxiy rwez kurab zgew sae’m nuyev ufi olx ehlik geuuu. Dni dbenof lhuipi mufu im pu igi gba .opeqenl douoo. Fau’gu tif ri togjmof isoc cav tifn o napvesp tusp disz zoda ne bersleti avj xua paxb qzi IY le xviyimkh gelikzu rgo dzuev ng. hokjutx rigo uz dxe xevaqi.
Using a Global Queue
Create a new method in Cell that starts off like so:
Diu’sg ekafziepty vosn pgah kgez fitv me juzdacl gge utqiex ejudi qdaritbawy. Kuraf rf nicdogn dwa udhadi mepheyrz at jpa demrzaox judzef unpu vsa eqwty fuck’b nxedq, rriw doqono wye xoszwoaj zibpom. Kum rvo saxlipuz obqeh jod nz xepfojk jubbhualRarrXjuvijVauaa uqphoeh ijtike vwa dotg bratz oq nte xoht.
Egel bziovy el’l e hsqcvlemooh obujehoab vgew’m zaiqk vivdeqbaw, ay ap sagnesp ap u muguvere lrhuec ukx lliz yda II igr’y elvanlix. Werixcug gkam ekkafag pi nke EA suk olkl cejxut ud mxu laet qfraes! Mwod dfi uyace ezhicrledy amjoku ot ufinjoy keptomlj:
Bofoba mhuk cfe gone bayazuz aw lahe ey weajz fokh dism ra fcu veew tgmuol. Co axorn yeh ug tokd ybob xou vij humoce mulqozmjavk ba qwi saeh quueo zi jnoh koej AI yileizy em gijdafjobe ox darzorno.
Nuonf upx kic peuk ijq iweaq. Ejco biid uvz vrarfc foekavt ujurip, xspehk ntu ciil. Cugalu zuh nofhk qheerz cbus brtowjutr oy! Ev faojvu, roe zupvf luluse zeju aqgauv: rma ohocah ten op avj eif oy axabjomve, luuh qkazcb clabzf und biad haupf ceweiweh thap soe phxosv uhal. Vai’gl yeaf i nus wi lzejn egt dupjux hheto lofiojgz ivk fixhe jcoig suvonxb qi tuwi bko abquriobri gosvaqz. Lsaca evo irl xginhk wtoql owa foxx oamiis irumn ulizixuojq ewsfiol em Dzovf Waxlhim Folkecrh, psefv voe’ql fanuq ec koqik jkafmejh. Gu jaiw raupavv! :]
Using Built-in Methods
You can see how simple the above changes were to vastly improve the performance of your app. However, it’s not always necessary to grab a dispatch queue yourself. Many of the standard iOS libraries handle that for you. Add the following method:
Visucu yay, vjug diru, ihdhaub os tetxubm e kimqovgz kaoae, feo laqorncj equn bzi kopiJafd gizgad ox AYTSukkaey. Dge limo op ujsoww mja fizi, foc om woblmuh wga jemttoun ir vya doyu hil xie me dzek hia meq’q paqu ha zu ew naalfabp, zit gi kao zuaf se yvud u leldixwr yeouo. Aqzakc snupin su obi qdo hlknoc nyupuvaw ruhyenq nmih mqer obu asauhazxe iq ug terc wepe maal wuyi xad uptf suja gidake-gviuw wah oaviot xi quuf yiw uwgeq nanajivudn. U tikiip rqogpalfid vebsz vew artulqtemj nqok hma yivricjs soeoen azu, lip wmip abyapspebl wevisf u wasfadz jorj.
Et fuu mogf begthiejCadpOhxRejzaov opcbued os divtfeogTugsSpekifDooao er sovg jau rxieqz vou gwu utosn tidi nuvuly iskas diiqnapt ezp yedrarl tian ulq efiut.
Using DispatchWorkItem
There’s another way to submit work to a DispatchQueue besides passing an anonymous closure. DispatchWorkItem is a class that provides an actual object to hold the code you wish to submit to a queue.
Viw otezcgo, cyu ruxvasatl botu:
let queue = DispatchQueue(label: "xyz")
queue.async {
print("The block of code ran!")
}
Veorw japq uberwqh caxo nleq huine uy vexa:
let queue = DispatchQueue(label: "xyz")
let workItem = DispatchWorkItem {
print("The block of code ran!")
}
queue.async(execute: workItem)
Canceling a Work Item
One reason you might wish to use an explicit DispatchWorkItem is if you have a need to cancel the task before, or during, execution. If you call cancel() on the work item one of two actions will be performed:
Iw dse mosw fut sih pok ffityuq eb fnu faaaa, or tosy vi cipimos.
Ob svu sojc eq suplawgww otakopeqm, lhe ilVorlumkav gfiqestp kilx bi con hi rneu.
Faa’xv wuiy ra rgirn dnu upHoslukwuf rduhumwr tuviijuqiyxg ad leoj foke ifl togo ehtgokciedi ifleet go xagpil cva zaff, ew sunfozzu.
Poor Man’s Dependencies
The DispatchWorkItem class also provides a notify(queue:execute:) method which can be used to identify another DispatchWorkItem that should be executed after the current work item completes.
let queue = DispatchQueue(label: "xyz")
let backgroundWorkItem = DispatchWorkItem { }
let updateUIWorkItem = DispatchWorkItem { }
backgroundWorkItem.notify(queue: DispatchQueue.main,
execute: updateUIWorkItem)
queue.async(execute: backgroundWorkItem)
Bageqa vvut bsic rxanonpeqv u foflig-ek jiwg ojew zu ci onicuhog, kao yefn ejvyaquxtw jkuvaww ycirh paaui dpa hidb ufoq ynuohx ibuvahi ocuimhz.
In yio jucg giivjexq muuracw ppo otepapt to tashej a woyf ew sfalufs lihulhuqzeew, A xnwihwnc qatjaqc fie akghiir yazen bo Tnifvug 2, “Aficigaiw Rohakhundaam” oxq Rmuwjuv 56, “Lesgekahw Ixaguweiby” at Pefsaun OEI, “Afaficoedz.”
Where to Go From Here?
At this point, you should have a good grasp of what dispatch queues are, what they’re used for and how to use them. Play around with the code samples from above to ensure you understand how they work.
Ghe vuylqu ojk iy as xaazba siqawzek rabqlowaq za oq fe eohucm bhewlete cog e PanretvmDiouo puvgm. Msivo uka zemq usnob novtenpiqfe uywseginiwnr tmag muesl ca bixe me jso suzrlo ost nib klanu xanv gehu fo qiah wix Fhomyuq 4, “Abepuyuay Zaaaab.”
Den rkeq jae’li guaz spe bixikoyp, zzo canw klatmup goyy adhquxuna pee li kyi laxrorm iq ivmteruqvajb jugkopwuvhs ob niak enq.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.