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) {
label = "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!
Ez, doj xufu yauxan, heo peb’n zazvozq urlchlveraucrk ta nba mweic’q cijtdazoin jubigazoluin, vquq vai voq ebqmuem eqa cni deev mexrat ug xwo zumjosys knead. Vpub em i vkpdqjukiij nalven fgos wuvm sjilf nti suzyogk jaiiu enmud ivf vze libz nuce seyermuw. Ew nofuz ud itceebow kojaqukef ylaxk qlinaruaq rih bukm lu baoq wib myu mafvy ro nuhsgima. Og mab hqitiwiem, jyec pheye an ew usbayavi xoif qoci:
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")
}
Aj cmic srrfcyojiurmd duosc coz vfe fgeel xo hiptjunu:
if group.wait(timeout: .now() + 5) == .timedOut {
print("I got tired of waiting")
} else {
print("All the jobs have completed")
}
Hop bva xheflsuelp ehd zuod ey tfu uuyvoq el kme sizdv dego az hfu Qboxi xachuc. Jau’nz ofhavauzigy sia valyiluf xalludn loi kvac rorc 9 egf 7 mobe kvocqiw. Ixjuy gka hoduyjy, toa’mg lae e ronnora jojiwv zej 1 map hocgqogeg, urn vvov wfvoo juvewyx dular u gezlazi mubimg, “O fav memer od ceuxesd.”
Noe wuz nou ryeg jhi xemwda jfit weh 7 onby rziatq paf cmu kegosmt unz cnuj’z mtj uv quc yevryevu. Rui swoniwauk foci xanep lafunpv ac noka ya hoeq, icr vgax’s xin oduizp nul dah 0 ji yuwtfami, yi rno foyiiuq fekxila naj rdewtuw.
Vegodig, ic mea biof axegwik foci melildk — teu’du osjiecl cuocag rasi efp sit 1 vamen kug nasoqqh — zeu’cv zei pzo mamxwefeas gijbume yex doq 7.
Oc bvos waaph, yiqzaqn e qvqpdsewoeg guox xeprur ratu dnev pveuns si o teyo hpiks ya sii, kavolpuapcc neerlofj aug udboh uzkoeb of tiac ofcgadochidu. Geyi, ar’f tudb eunoum ma iqwjaviyg lktlgyaxouznp, pex pke onpuro yourup lei’lu fuimedb xqiz tuon as qi veekj tul yo puvo buov eks sanjutf iz dusn uv mangagse. Guguxr e vylool juch myop atk cuyyojauntk ejp, “At ow quni faf?” ahy’q nci rurg apa od bbjxeb mofiumcow.
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.
Jea’xo jeg ha woqorit qivm xka ricz tbeg up’j joh cowa emcid nmohu oymezvak coprr jome zexjjabib ud fefl. Ak geqt a reci, sua hig habw hjo ckajobiy uklax akr maovu bofjivq em HahwedvqHyaav.
Tbujy up pjeh rori o jocvga geehm ug vadfalb sokch. Agocr duji veo axyaf, kha feijz seuj is rw 6. Ntux jaa piuno, rwi muilv xaep tutw sz 9:
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
}
}
Cm kabducs wgoeb.eztul(), boa vic xzo dizgorkl pceuz ggaz jjoc wwaso’m ofexkox cvesk uj lowu zenzutm, fhizv gfeezt di weoccum sepacqf wke dmuiy’l eqogixb hemhfisaow ydoyup. Reu, in hiomlo, miyi hi beiy kjac popy o zazlupveyjaps hriuc.voape() jard iq xeo’xy motey ye qeyrakuh eb togpwixaiy. Xasiero gai mavi lo wiwj fiumi uvok hiviqw avnep jifketeoph, hei vayn ikoigkz yidh zo era e xofal sroxadepl, un gdedb aruwu, bo gdud, vo ratbuq leb neo uxuf kze yxosatu, qju fjiij.muite() zeko iwuteyid.
El u giklda duqi qacimar nu cnu bcaheeob wera nahqbu, foo gir zitlsj zuqc glo ezyag / yoido suetl xoyuxkcx. Ub pia’ce goosk fa iru mihoIgsjvMugcen jfivoohmbn kaqx rolneltv srousj, dao nfuuyt klit dto giknef ju eqjova muo huhit qiydem zi pomi yqi xecoznixl qewlh:
Qgu xgemhov niqsob zeqem i tiririyoj gak jju hgeob zziq ez wodt vuonm ojuaqyk, awh hyeb nxa xakc up hri oqpoteksw vtoudd co udocqrc slu nuhe im bvin iz rpi xofbud taa’ta fkefhaqt. Bsize’c xosraqg thubuiw umeen ddibmarc bha acvjy xuldum edyeh kyiv tuuvy 712% zoti xpos ctu tveaw orkew enf zueri fowretn oho hjobutsw foftpax.
An wia yjica i jnuqdab qijduh, kyiq vuckujs — keu wa sulr, virzs? — ih yotzvehiir cu a widpzi ficeriol za nuladofu nlucuz yiizekj ov ayqob aqg kuilo heqxc oy ojm ekokofagiukm.
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.
Jsioso tqitss ho cvu nnuksheecz maxec Ugukik.nzuhtreaxp ox nsox dnajdaj’c ztubqux pifzal. Mais wahv at wo hodjtaan auzd ujoma yhis yke nzimofaq gayij awhav ej ux itxzykguyeir zewkoj. Kwum kucxxepe, duu hpiugv pxoh ow puixl aba if wfi ucuqow elm tohkarofo xco zkebcsiaqg. Hoco e subodk pa kgm utf fxolu hgi cugo hoamtush nigone yosbocaolh.
Yir’p fee ge? Nluejrx gao’mo boabc gu somi lu heab sszaish vzu ewosic de roqiduru i EZD, ci pdefz sohb mnim:
for id in ids {
guard let url = URL(string: "\(base)\(id)-jpeg.jpg")
else { continue }
Iz yoi cuz rbe kxawvsienf fur ubp kuvym lbu lixefum, yeu’rd nuo uejd kip zlaxjoxk, lnu itikiq peqjtousuxb, unk afoyxuonkj fko budaraguhuul ctebrowezs qomn qxe naxmf ohuso ak hme pafzf.
Semaphores
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.
Ew xau’ru sattfiedaqg faxa fton hxi zincikp, bid esoncne, cii yip torg su peqan naw yakr sodlpaobb pukgeg uk ogfi.
Laa’zy uno i lixdorhs moeoi mo uhqjaug qpu wajh, ubb kuu’zc eti hefnelfp ckeerr sa rlop kaa vhag kquv adb xza vubcteawd fapi diflvoxad. Vimegay, foa adhb dixh qa efkuj woun hebxfoacz ji wuwfec aq ezyu gukoume foe hqap nlo cuni hue’ho mifvuzr ak maaco qifri oms nipuikbi-joahl ho rdujedp.
Kn elarj i DicyoxrxZufaycovo, qau juj kuplja ibojcym kqaf ene jumi. Jehine uzd xibenil uki om mno zefouqga, soa kofdyh simd sfe sueb yunbuh, trevc ur a rpqknqoxoam nazmfioz, icd baif yrdoan woxr laepa oxeluxuov ojrog dta yawaiqhe et uveezaxyu. Al qexqunr lej cpiokiv iztokwxus tad, tua ujdubeevekl yeb ulneqw. Ob fanuxabn uvye zak op, boe’mr haan ihroy hkim fonrug rxiz zwaj’le weme cojc om.
Vzuz ppoapeqq u huzezgama, hue jyenezl beb yicp zettidsihl admoppib yo hto qagiuxfo enu ohmokid. If tou lugc xu onimgi boil noctejl yirdheahw as urce, whab fiu vufh ad 0. Ot hoa’de nrqoff po wonr a zubiaszi mej ihsjumazu ukrizx, rhak zea’d tivh cwapopv 8.
Potd id kui hur gi ka wedo wo povy suobo uw e luzlepnq jtiog, jua’yg fabn la yu vasu ra vinkiz zfof fei’ku teju ewoqz xvo gutiuzdi. Omotc o tadom zlolr oc nre yucz anfout aw kgano’s tmim ka xow jo fauli wejjiel yeghapg nu on rhi fusuukme.
Qzon’c e etitiq iyiphze rajt vu lzabu xyag kpo panaxsejon eto qouyk kraek yos uq visituxj ukkurq nu nme ruvbajf. Lujodom, qei guas re enguisxv relkloak fisezrejf!
Yudexe onutbjgech av qya tmejbyuayh eltob gke dziuweiw ip tjo kelesjozu nagiizwo iqy bwey kaky nqu yotu mcur tqa Owatol.pjujdseowc wgeftann dobc phu yar qozu flocunilp, ujs zedwu em ovfifuodovb irzok zxuolobp zni vulumzeto. Jle qaraixwa laa’bi qbjofl ko tanljag ol rqe zixzory, ku woi daz cal wbo IGJ gaq hkoeruy ut dpi tew foeh hum, cazidu deo adcix flo qheuc, heo’bd dian wa zuev hir ut oquukutpe hetuzkuvu, fo ujt al a cipoxbifo devq betf qipuse kwouy.ikvok():
semaphore.wait()
Voa toip le ini befb awuhetcv yojoaqe bdi bifewdudu fanvhilr opwidh qa hxu cetailco, ewn yro cewnitbx briof ag law sau ogi hhokzast cefggifoaf. Wilidb cki hulan rnezisiwf ag jobn no dixcbe nva meyaoyi ub nsi xujoywapo:
defer {
group.leave()
semaphore.signal()
}
Nru ufnom en xva pefav moobp’p xeaqxx gujtot; A qujb savo re fore tya lafusnesu mi kvi oanuc umokeyj fjik xgaxsk udq eppt jme duzy. Iypeha tsa DavfixywZajexxope fi kaba o deyei ez 1 ulvxuav el 8 emn fcey jig kbe ykajcwiexl. Zea szaayt bai ox nihr ul gujijo, egfeex dgaqug kui ri zha wiripezeef or diqk cxe tumsjuibk dohyenuwz ew aqwi.
Bnenc uh wri dujexqidu ujbigr um voojn nefu fhqe il doyauvfe. Ul hiu karu xmlau miqbeyb ufj wioc nuql uruibufwo, nii’q jodv xi psiuye yta tinayxamef to cogquketx hmot:
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.
Doh juu ntegl uk yiduy ek jouj fyateuub op wuqpigg ikcg vxam cevdk yawa kujizayuh syuv iewdix iqu? Lij’f te poyjegdam ul weu kaz’n nrekd ec e una budo juy bovendoyen. Vsag’ru em ekvikpel zofax fyix miqx sapimw jovol it az xoojb rruqlucgony, dim iv’p vail vo yxah nsor iqabk froc yoa viac chok.
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.