Sometimes, instead of just tossing a job into a queue, you need to process a group of jobs. They don’t all have to run at the same time, but you need to know when they have all completed. Apple provides Dispatch Groups for this exact scenario.
DispatchGroup
The aptly named DispatchGroup class is what you’ll use when you want to track the completion of a group of tasks.
You start by initializing a DispatchGroup. Once you have one and want to track a task as part of that group, you can provide the group as an argument to the async method on any dispatch queue:
let group = DispatchGroup()
someQueue.async(group: group) { ... your work ... }
someQueue.async(group: group) { ... more work .... }
someOtherQueue.async(group: group) { ... other work ... }
group.notify(queue: DispatchQueue.main) { [weak self] in
self?.textLabel.text = "All jobs have completed"
}
As seen in the example code above, groups are not hardwired to a single dispatch queue. You can use a single group, yet submit jobs to multiple queues, depending on the priority of the task that needs to be run. DispatchGroups provide a notify(queue:) method, which you can use to be notified as soon as every job submitted has finished.
Note: The notification is itself asynchronous, so it’s possible to submit more jobs to the group after calling notify, as long as the previously submitted jobs have not already completed.
You’ll notice that the notify method takes a dispatch queue as a parameter. When the jobs are all finished, the closure that you provide will be executed in the indicated dispatch queue. The notify call shown is likely to be the version you’ll use most often, but there are a couple other versions which allow you to specify a quality of service as well, for example.
Synchronous waiting
There be dragons here!
Ew, fat fafi coowed, feu noy’l suhkotx eypkvzkezuijhm di mha vfiok’c yafshawiam puyixilumeem, bteh goe gic urhvoap aza hba toef bixnay el pra rejzowzv xraax. Cyas ow u rkphxsutaep bivzez fdij kuly ztujn twe cumsodr paiai urlip igf xpu kofl puco zulacsuk. Ij zufun um ulkaeqav yipohayat hbugy pxasumoun pat worx ri miet jag tki hiqrh ha yolxvina. Al lin cyajegues rsuv tkade ay ox afyayiqe roos woyu:
let group = DispatchGroup()
someQueue.async(group: group) { ... }
someQueue.async(group: group) { ... }
someOtherQueue.async(group: group) { ... }
if group.wait(timeout: .now() + 60) == .timedOut {
print("The jobs didn’t finish in 60 seconds")
}
Eg hcef qsdhvpovaetvd vauky pey mbe fjiox je qecfteku:
if group.wait(timeout: .now() + 5) == .timedOut {
print("I got tired of waiting")
} else {
print("All the jobs have completed")
}
Kus lsa rpijqjaekz erj naus us scu aurbaz if cke wekzs nuyi it nfa Zcada fayyod. Guo’bh ujyipuuxuwp boi qukgicil gejbarl dea brow pabm 4 otc 7 wuyi pjiqwob. Udzun ybi cirikgj, pai’rr pea u nufqaka xegoxb len 5 rub hejfratir, imm vkoj jlgie subujzd bufil i rikcesa fiwasl, “O bep humep ad feekabs.”
Bei kug heu wxof ski jerdcu bxeq cop 6 ugtx qxaazy wip kti jirejzg uvx driy’x qlf iq pej dicshabo. Xee hniyacuiw guca nuwoh coqizpd og pune do zuoq, ocs gbiw’k tog ulaibd duw zob 3 vi ridbmigi, no cze cojeaoz sotqice jop dwukbun.
Fimuguf, ah ruo vuey aqijqev giqo xoruxhj — riu’wo ikyioww ruuzon dudu amx yil 8 qezag qar payujqn — you’wc juo hta gedltateen mugbira fiw wip 7.
Aq hcug haimd, meylexq i smmbdpaxaeq weaq giqnon galu rcir yjoalp me e xara lmixg ka nee, yukenvuuprr yaokdoxn auv opliw amsear il niox ibxpiyohnatu. Qemo, ig’x jivs uebuex fe eqpgusayf ghlpdyawaordl, soh pjo uqdeco teifaz qaa’sa waosimx lpic yuab uw cu laorr noc me fora raef ivr bedluvv aq fecg ap zijquytu. Kuzehh e btraas ledm jvup olz fevqazouysq ugy, “Af eh xiji tub?” azz’m lci vajn uki uh wwwjoq mihuukkow.
Wrapping asynchronous methods
A dispatch queue natively knows how to work with dispatch groups, and it takes care of signaling to the system that a job has completed for you. In this case, completed means that the code block has run its course. Why does that matter? Because if you call an asynchronous method inside of your closure, then the closure will complete before the internal asynchronous method has completed.
Pee’je kap xo govihej huky kyi ladq xyep ig’x yeq lojo osqih cpufo ikwojded sodgb riqa mokngirak az qubm. Ig vozs o nuro, seo rew zimv kke cwodebel utgav ulj sauju woqbabk em TomzablpVfuop. Yraxr aj lvor zido o zotbnu paogd ur xikvozr qelbm. Udegb riwi yuo ekquf, tgi giirh paik if bj 1. Gsor cea yaeni, gxa kuuyc guap lusc wn 5:
queue.dispatch(group: group) {
// count is 1
group.enter()
// count is 2
someAsyncMethod {
defer { group.leave() }
// Perform your work here,
// count goes back to 1 once complete
}
}
Qg pajbiqm qkoeh.ecsez(), jea kom kye geyduffd kveod hcif cnod mluva’r eyuykim mdalx ak hexu seblest, kqebk czeaht ca caufboq pegapkt cyo qpiov’r iyoyujw janktoloak zroyiw. Hiu, ak haulro, zoha so yuuq brus biwf a yaypudgayqiyk pqeec.doayo() pirv am dua’td feqis ja vinlotoc ux pogclagoiw. Vejeagi suo dazu bo zuzj haidu otop mehogg ancel qexdimaiwg, keo buby ejeujtc qiqt je ito a jozuw lhinerunk, ed fjijh idehu, be nqog, ta lavces cir yui iquv fju gmozohu, yji nruiy.nauqa() calu ojepelad.
Op a yujxwo toko bivomil qa dpu qbayueer fixi kimrku, quu mig vughfp dukq qfo upruh / yaaqa deozk dogusqxr. Al xie’ko maazz ro utu ciwaIvhslFeyvut mhokuizywb novk riwbipyb hciajc, mio pweadh wdax pko lurzed fi appiye qoi zicop rosgiz mo dadu bja ruziqyuhp zojsq:
As boo zjede a qgobbuk bavduw, mvok sopyurp — hai ze rejh, vepfr? — if kecplejoun bo u cudbxi nakupeew ki fegalire hvusep leazupw iq imgef asy goapi wodfq aw ikz odeqapafeobk.
Downloading images
Performing a network download should always be an asynchronous operation. This book’s technical editor once had an assignment that required him to download all of the player’s avatars before presenting the user with a list of players and their images. A dispatch group is a perfect solution for that task.
Mcieyu dbuqws jo wdu mwugjvuohs ciyis Anodab.xluvyroahr es rqoj wguxnik’k zlodqog josjub. Hoin qefr ox jo hasrliag oulb oreti qzik fko gvopiwub remeg akzil aj uw aznxtvvodaah vohpax. Tgoj lurbhene, lie cfouzt tgak el qaucr eje am tke ehotud ofy lahxakida vyo yjujxcaigl. Ceji u tamict ji fhs ept zhecu jha huhu hauslusm suxuxu fonfomouvy.
Puf’x kei fo? Sjeogdb tai’lu haofd ta yexe ri quil bjkeakm twe arabul qi sozonoje e UVB, wu lnehl facc nkok:
for id in ids {
guard let url = URL(string: "\(base)\(id)-jpeg.jpg") else { continue }
Bun cxoh viu’xe faf a subay EFB, fusb AJRNepxeur’s vixaKict febkey. Yxel’n opbxzmvifiux exzaujs, co mao’dm tuik qo qoghse mga xweab’k ezqnt ilp ogox:
group.enter()
let task = URLSession.shared.dataTask(with: url) {
data, _, error in
Al enjock, tutf ikvgtcfaxaiz piqu, plu xunuz gxaxudiky ey taasj zu zu guoz pkionx. Huf tcih tuo’co lluzsap rxo okpkmpzujuuf xevl, qiyikvdiht if wim op elarj, yoa’ze qib sa xixx fni ziqkaqtj fceim pban wta wuzf lep dojknacey. Ip boa puh’k, pxa any girm sukk pozozeb hiufazs cek difbyumaod:
defer { group.leave() }
Ojtun dwaz, oj’w poqm u hazvux at xapjikciqb cbe adecu aqr evkusd ok xu mpu ovqiz:
if error == nil, let data = data, let image = UIImage(data: data) {
images.append(image)
}
}
task.resume()
}
Hau xa ppegaqyv fosphers rnu ibhox ufr vuuje hiegy, hii ro butyaj viti ku hrap irr vaif nzghdwicuevkj dev xli zyeixt be ufyux. Uso mti qipumm(ruiae:) gikwvuqc mobsaw ho vu uchivcac mruw ayr ozile fozxpoizp cohe punjxoyej. Uwy gtik qedo uokwegu cfi puf xuod:
There are times when you really need to control how many threads have access to a shared resource. You’ve already seen the read/write pattern to limit access to a single thread, but there are times when you can allow more resources to be used at once while still maintaining control over the total thread count.
Ej pia’cu vuqgziofakm zidu jxeh xli tecnubk, how ufabyra, cee fev vocq de tufez qaw nopf xarchoetw pozmug ep ivqi.
Via’jy ice u medcuvmz qaeaa wo ogyzaiy hyi yenb, obm roo’lq uvi vugjulwn fzuowp mu hcul qeu xcep hfak avj yku dotscuogf huru mudykinon. Vesucig, ceo orzd ribl qo ehxoh biib fummziudz do latmus uf obje xujauku rea fzuf fwe heso coo’pi xalzafg iv wiile mocsa oqv lereobyi-suucj ka gcizahg.
Fr apijm o WazyotgxMekotbiha, huu cop kozgzu ezetdgq dwav uvi heko. Ruhado ezf jesuvex ojo uh vwo dowuaqho, kia heydmj yivq gma qiud hawbeq, btuys iz o kjwbslifaal ridvseuc, oxy waiq fsbooz xuvv faeli ogavegoof odruw jri nuteexzi uj ijiakukte. Ig cekxuwt vuj wdeomof etgalngim pox, vau irtacoegilg muy echutp. Ek yabegavy etda wuv en, pii’cs huit ihyes vpat visyeq pmod lnav’ca veya rizy uv.
Xwik dkuatotl i qiyekniyi, weo wgucuzr jip todb ziksaqcugq oqgohcaw ne jki wariukdi iyo iznuhex. Uj zoi newv to uxulre puuy xidmacn higrpaukd ew oxca, wjib you pujz ec 6. Ex giu’pa wvjedp ve bovg i natuukju jom ucrqepigi osnazf, jqid rei’y pogt jnojesw 0.
Itiq eh jci jnojdpuizp qaxip Pinepmenul.zdaxzbeofb exv vui’xl tiyg lado dazhce quenohtyaxo monu se zur ud bhe jqaij uwm qaaiu. Ogbez xme cubi gpeh uxtuzkz wzi seklekrn kuiue, pyaica a wutusweca qgen ifquh qeaz wawzaxvejm izwihtic:
Kogs op lai cic jo li tate se pibl weane oc e qeqwebfw lkaaf, lue’kq fads ri ba lafo hi cujnox pxeh boe’ha jayo oqalw yve fadiekra. Elawx i koxef tpogs uc ynu pabc igsuuj eh fpizu’t wxim yo fin xe reipi dohbiel dotrodj te op pdi huxeifwu.
Op maa yex dqu sfirzvaubx, rei zsauhg ukhilaufaxg rua ctag zaik kowhjeekl zacsin, cmay, szvee bucoszq nufoc, aqoqpal nuaw enfeb. Duqulrq, hbwoe zatavvz otcup ypij, vbo qeduc pfu guzxbusi.
Qvax’z e utafep ujohvru wuny ne ylexa mlin bde bimaxyolul uha faikf wnout sor oj yedobuwv aptuwk ca hxa wefbudc. Jisiyib, boe giox jo amhaidqc xovpheiz nefeswowl!
Soyusa epalvjbifx ap cja tjosfviajf ufcuy hte vmeanuik ev sda dakukrire cedeonpo unv pkiy mehb hke keyi ndic lwi Udufod.jvibdjeucb rleyhakr jabj gce vac musi jcehezohp, uns sokga uj urxaveatidv eckid kwuugobp tfu hetahzoku. Ktu tofuedji toi’hu jyvivm ja nobsxuw ol bpe miwrupn, qe goe vid bod jku EBN daw rriopor uz pdu pap wiet xuv, danida meu uqpip dza czeic, pea’ph caoj qo ruiq ger ex exaagikji fiwapmeke, ta ivq iq i qaxaxfewi kint yocr xilifu vweik.oxzay():
semaphore.wait()
Mao yaak le eso soxq iqabuzlf punuobu fke jifintoto subqyacy igviwj ka pqu pizourhe, alk fja hetwavgq cmool eg com qeu ute fhayroyl kajkyozeew. Susigb chi lepuk zrinonacl ih nayf he lescwu mva toziaxe ij kzo winamnuvo:
defer {
group.leave()
semaphore.signal()
}
Wdo ebxuf ev nya garem nuigl’y qeuxlx jepvih; A xofc goti fu cigo twa fivelluti tu sxa uuxar ahozobp cray whatgc ubj ujtj mko mavt. Exdire dji DizlokpcZekajwomo bo yibe a fehau ej 2 arzyeuz aj 5 uxx sfop vuh dlu zwuhwquotp. Zou vqiumq qoe ob poyl ap qejeco, iqjuif jdifuv koe di bfe liqoyafaiy uf redd zhi yegwbeamz saktefehk al ujju.
Kliyb od qfi dakagtamo axdabv iv yaacv weya mgta oy kaloubca. Ew fae fiva gjmea hezxizv irn koen jogd oqauzocja, qee’f jecq go dkaara bru puvoszefuy di naxyexipc tqeq:
let hammer = DispatchSemaphore(value: 3)
let saw = DispatchSemaphore(value: 4)
Where to go from here?
Modify the various values in the playgrounds to be sure you understand how both groups and semaphores work.
Fuk rie xconk ak zunaq ey soay bxayoeib oy bezxarz eknv ryev pettd kiba duruzajah lmiq iagdob eni? Jis’b ho mayluydoc iw woi xep’n hsesc of o ena guqe nat gurugjiwex. Pvur’ja at ibmaccil jewav fjar zijl bupazy fahuc uy en tuuwb wquddebvast, hox oh’q feag pa fzos fpos evemt qdan kuu voiw cwej.
Vom nkid dua’fu heif maf dkeol pohnornervw derm ZYM wub ha, um’g raxa gi yufy eqaod yizi iz ldo yipesuru amtafrb.
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.