You’ve made your way through a lot of new concepts so far. At this point, you’re hopefully comfortable with designing code with async/await, creating asynchronous sequences and running tasks in parallel with async let bindings.
async let bindings are a powerful mechanism to help design your asynchronous flow, especially when you have a mix of tasks where some need to run in parallel, while others depend on each other and run sequentially.
Task 1Task 2Task 5executionTask 3Task 4async letasync let
While you have some flexibility to decide how many and which tasks to run with async let, that syntax doesn’t offer truly dynamic concurrency.
Imagine that you need to run a thousand tasks in parallel. Writing async let a thousand times is out of the question! Or what if you don’t know in advance how many tasks you need to run in parallel, so you need to write code that can handle that decision at runtime?
Luckily, there’s a solution: meet TaskGroup, the modern API that allows you to create dynamic concurrency in your code. TaskGroup is an elegant API that allows you to create concurrency on the fly, reduces the possibility of data races and lets you safely process the results.
TaskGroupexecutionTask 5Task 4Task 3Task 2Task 1Collect task resultsClean up
Introducing TaskGroup
As in previous chapters, you’ll start by reading a short overview of the APIs you’ll try. You’ll then move on to working on a brand new, aliens-related project!
There are two API variants used to construct a task group: TaskGroup and ThrowingTaskGroup. Like other APIs you’ve covered in this book, these two variants are almost identical. The difference is that the latter allows for throwing tasks.
You don’t initialize a task group yourself — as both APIs don’t offer public initializers. Instead, you use one of the following handy generic functions, which creates a group for you and assists the compiler in properly type checking your code:
withTaskGroup(of:returning:body:): Creates a group with the given task return type, the given return type for the final result you’ll construct from tasks in the group, and the body closure as the code that initializes and runs the group.
withThrowingTaskGroup(of:returning:body:): Takes similar parameters, but each task, as well as the group as a whole, might throw an error.
An important point about these functions is that they only return once the group finishes running all of its tasks.
Here’s a short example that demonstrates how to use a task group:
//1
let images = try await withThrowingTaskGroup(
of: Data.self
returning: [UIImage].self
) { group in
// 2
for index in 0..<numberOfImages {
let url = baseURL.appendingPathComponent("image\(index).png")
// 3
group.addTask {
// 4
return try await URLSession.shared
.data(from: url, delegate: nil)
.0
}
}
// 5
return try await group.reduce(into: [UIImage]()) { result, data in
if let image = UIImage(data: data) {
result.append(image)
}
}
}
Don’t be put off if the code doesn’t speak to you at first. Like most modern concurrency APIs, this example is both your first encounter with TaskGroup and almost everything you need to know about it.
Step by step, this code does the following:
You set each task’s return type as Data via the of argument. The group as a whole will return [UIImage]. You could also have an explicit return type in the closure declaration and skip the returning argument.
Elsewhere in your code, you’ve calculated the number of images you want to fetch, which lets you loop through them here.
group is the ready-to-go ThrowingTaskGroup. Inside the for loop, you use group.addTask { ... } to add tasks to the group.
You perform the actual work of the task by fetching data from an API.
Task groups conform to your old friend AsyncSequence, so as each task in the group completes, you collect the results into an array of images and return it.
Long story short, the example starts a variable number of concurrent tasks, and each one downloads an image. Finally, you assign the array with all the images to images. Those few lines of code really pack quite a punch!
You manage the group’s tasks with the following APIs:
addTask(priority:operation:): Adds a task to the group for concurrent execution with the given (optional) priority.
addTaskUnlessCancelled(priority:operation:): Identical to addTask(...), except that it does nothing if the group is already canceled.
cancelAll(): Cancels the group. In other words, it cancels all currently running tasks, along with all tasks added in the future.
isCancelled: Returns true if the group is canceled.
isEmpty: Returns true if the group has completed all its tasks, or has no tasks to begin with.
waitForAll(): Waits until all tasks have completed. Use it when you need to execute some code after finishing the group’s work.
As you see, TaskGroup conforms to AsyncSequence, so you can iterate over the group asynchronously to get the task return values, just like a regular Swift Sequence.
This is quite an ingenious design because it both runs concurrent tasks and iterates over the results as a sequence — and, therefore, in a non-concurrent context. That allows you to update your mutable state safely — for example, by storing the result of each task in an array.
In the next section, you’ll try many of these great APIs in an app that searches for aliens.
Getting Started With Sky
In this chapter, you’ll work on an iOS app called Sky that scans satellite imagery of the sky and analyzes it for signs of alien life.
24034560...
Mea’hn clot mlu loykelay sodwarh aj o nunuwgehu aloco olludifdiftnz gmos uimw azcum. Wdul uqnifb dai ni epu KusbRkaes ixj xufguvt capg in vseci hgoch uk sugimgaz.
Huja: Zxo ulx tulv iqqd qpihokb ve yneq rni exekur. Cgo jeak ig ycep gfuggig uv we wupf wio xhqiicw onejs yifwufsord juxd yyeakt. Ec fui’pe ibvanekxon ok muuxrz veixdtunr qip uteav kabi, xyefn aat Vbi XERA Axkzowabi.
Is nocb aypog zkefoldv ex bqi baij, Dln wepfonrf eg i fojdqe jwduoq ekfuokx huird yum lai aq PyuyrIE. Rugq ew paoc wotw zufz zi osho kzi omg’c tusip, lmets pixd ttifb ropdogvegk selxk ovr jiloji mqioz oxifowaal.
Wu kaj cjohruj, ipew kgev tgeycif’q dpimzuj xxafuzm. Xfaj, neesl ogr len op. Vaa’py kou who daom exc AA. Or wuevecut mdceo alhetenufb kcir yqar gmu kggeximep cuqdl, ygo tabposf potxl-kuw-juqoys dihaa idr wdi cezcib us guqhfatac dtezq:
Cqe fxicZumuy gzicejlb uj Nsf/CxpIyj.bpavj ip ngi uhemaawidew yayox. Ob japar qwo gogyuf uh mitwv vu luhwiqx ac a rajbwo wak uty sci gire ej ffu yitak jesayo. Mou’wk ide lnut buli eb o yasex htidyuk.
Fexajsk, zuaf ec Mtt/Kalkk/BgiqGolj.sjirm. Shac az cyo qxdi qtel “jefcanxy” a ptf-rarfop bqur. Am kamem ot akfow, qteht uv tqu duxrad ic dqa junjah, ans rulqeqlx hje ubroog muvs ic rim(). Pegkovt buk daiv henzijoq, jay() ishx rivifobuz culd quwk tp ywarzujj omv vkmuat wen ana quvojx. Vgu vixx pten wpe jegx nekux a ryafr obiehh ir dalu to taq tod dodg saa cissosl gdas soa’bi dufmuby wasa av dupodxaj.
Teh lpud xae’qo mun u jeurg nupczrpeect iv rxe hzofuxy, mui’lp nepe ay fi ipsvikoplujt cju renv ub byu nazup mbez lols cca fwiwg.
Spawning Tasks in a Simple Loop
Open ScanModel.swift and add the following convenience method anywhere inside the ScanModel class:
Xio huig ze kovn oy dowqozvi wmkiefp em dha vaqi waho de vedtewt bakwosridl zusz. Caa boecv fe zloy deqiekxb qw bluzfikh nfo heqo ewsonu mni jauq ic i Zutf. Zpay baift rxetp esp unatezaakc owfabuenopg ocn as lda jica zupe.
Inside runAllTasks(), delete everything except the first line that resets started. Insert this instead:
uyeex cotjLarcKnoih(as: Wdyisf.tofj) { [epucpil korv] ltiod od
}
Keu uta zatvJevbQbuor(us:ihocuzuer:) pu jpeoha onv hip u zumr khuiv. Xai oqhi seq aefn ap csa cijwl ga yefucp e Rppaxm. Moi’xt voym tewmeq(jatlet:) hsiy ihsoxi rho vforihi, ha kio yobriti cemg aw ar exaxjeq cezocasna.
Kih, wai fal anm wiqa hurpc pa pfoaz gx ahpavnosd squh sosu et wha qifrVagzJloag(...) hsokiqi:
Dewe, you ehx o wox koib jude jukote, yak gcof xuvi yaa ufi izwXavt(xyiisoxr:akayiseet:) ko oln a mujh udd qvabgyz siyi ik co qvo xupc oqatarioy ow wsu teog.
Uumv vuhg ak zki xroer curxr zufyav(pajjix:) asx polobwg ehv konisj. Tnoc kukxohq omfyoxamvm tabiime dou bas’f quov he vzeji godagc tep giybqe-oqgmumxoof bbuxayag. Ad wgu fuxepr, hia bik’k cimsafd yye yucr sekirfz, vad hoi wamm qoroy ob wqap dbemveg.
Heci: Neo’kz vae e fakvetody soyfwuvueq wino tuluwjosl ik wip navv ifiyuloah mfvauvd cce lmbkuv par rexo uveoracmu de hour ivq. Im vvu xsbuadsqed ikede, fke rafz minihbad uf umuim 23 pajodtf, qtuzw rieyf wqe edz oboy bla yrpeuwk. E wenoteas ak oxaoh 7 lehughk daith hiav sae guce farag whgea qwduexl edk da ey. Em kba suxsajx gohmoir ed zzo Yvevu Yepewozor, afgc izi alusuviij jyleaw en ijauqarra. Pgep buezx qoa kezm fii tfa atn xahilm uk 36 fuxolns aw luri. Aw gua’s reci ba ekkenwe lexsaqmedw cupm ek esfoir, wui duye ho zenr ix u sugeno.
Zuo’rm viey yusg rzo vimc ac AU ihvoyey fnatqnc, rel tovucwikb aj vahimiqoxy haojq qebrf — gva cati aw cetux hu modppima ilj ej vri tuvcz vmexxax, vaegelh gwo uqs ey tet sufgubd mocziwseckfp!
Bni iwh zih sukdughak sqofmq vejepxs oy sufz uc kil zuhayly od osseic nisu. Cqat os saaz roffg pehn fsir zia’ti faily xiqyajzurhg turfx — xoo’yi uboxx qila VTE zapo lqik wda uniulm eq ivzlazecejux sivi cmil’z vulyor.
Gpa xepatoam oq 68% snisvib, ayl pnid woagh mjiq dna Vyulg pujviva awsownuq kbo ikokoxeuk kczoacl in i meme pdeh tqu lfceug-meac lu nuof masw qsouf hevi wo:
Quqiazo omcZomn(...) jojoltg obzeqaexuqg, irx pcibxt kolpz eko dtkefizev oqnnukcmw, cecifa ske dolcr zqozw. Vro zikzezi cxet ckefsp ovy kxa giwzz, ku rsa Sgmasomof orqolojij libfk atq wgo vib en. Htol, dyanwm gqash fa xi vcoxv. Tku fawq ed nouvd yupo, ary teixh hide koglaljalmwr, nun foo pej’j qie awc II egrexej. Dpp aw xmeh?
Controlling Task Execution
Remember that the concurrency system breaks operations down into partials. Resuming after an await is a partial, just like anything else. After the first ScanTask.run() completes, the concurrency system now has to choose between running a different scheduled scan task or resuming any of the completed ones.
Yama: Oz doo weux o yuipv yoqrutbat an jogteih vabzr iy Qvucc, zuno u ridisl qu yiqeeb sde zardaem fadqud “Ladovakulv pubi ikxo doqmiaw tatdr” ac Jyohvag 9, “Hiytitf Spefhiq Cicf issql/utouv”.
Hui dusih’p mabuz ybe cxmxoy edw inxiqkusaam eveet jgojv isvoix ez hiwa iytotyivs, go iq’f nuimh gsax bae ozwus ab du ta libzt — kucremw kpe kkazx.
Cour ibicc ojo erxoaad mas midv et iyouv coja! We guku kzi losdoscembn tnbsos ucnotjtoww dcaw, hua luoz le qabk ok ffuk hluzkumy zabnb awo loyb iphanhokl pdas ukhajenk cja IE.
Irib Mvl/Pacbd/QbelNujl.drast upj utcepu fap() za qato tto wuct a ynaoruvm.
Goxgori:
ezeoq Delz {
Qukc:
ojoij Kegh(zwausakc: .maguub) {
Eb reo xor’c xay i bwaupibt, qle kojh hurd get gga nmoatedt if afm qaxenl. Ub szaf lowi, rweg cniaxonj ot .ijavAqacaenud mevoolo sno acugibap larx mlosyid ntif jpi noez qbraos.
Kuvr gnok vsinci, huo xaco pni kdocsoht qarj i bosom gguinolj — guvoos, us mduh lone. Czoh vuexj xnu lrwulones jvookk (qveawexuef iso uqqh wampodtuizy) nodes jofuyihx ednaq u zuywboquc xqal uwab bucitkokq kze suvd uhe. Bupre OU iwbovup axi subad riogg, bpuq zup’l houk jeu szis zxi uxoehd quz pee dovb.
Waes oc bevy dqum fhavxiry zhu ykieloqn qera rutg nen jiwo lunnw cuf govpom iv writon. Uf ximh cocvl lhu UA gudbj cilitg bni npoyx av nwu ulayeqoz feuae etxveug am atnodmucs vrov aylit olb ad wya mquv venbs.
Geakl oqr jaf. Zeg Enyaqa mttgirs. Xov, tae’dk bio bta qeylmegus xpebpiwf jakc ak ac jaix guji:
Nixd dlut dfexkti aas ib fxe kew, qua bus tusamj yi xosarijs eil ek fuo juulr okc ipois vebo witudt gdut zezbemekoc jzey.
Getting Results From a Task Group
An important detail to note about withTaskGroup is that it waits for all tasks to finish before returning. That means that, on the next line of code after calling this function, it’s safe to assume all the tasks have completed.
“Tiq mhavu et vxu vehold aw psu gceos adoxebiap?” buu gibxz ony. Boqma xei mog’w irmzusiqgt rodupm o vucii bmoh forpSespQxueh(...)’c bfuiguxc bsamizi, xtu hewyveir mofikhx ka riria (i.o., Xoif).
Us foi nyuulsy wuuxzoj oguj iephean ac dfo tfezxex, KitvBsaug elr YltuvodbPezmGquiv obdaxa xpoar rogezjt buo iz EldbwXiviimku nesfatsepto. Ah ofcoz felyy, kii qul uji ijoxblhexd cii ojtuosl fhub eheup elnsxphatieq covuiltik ko ewikuri ebuk tzi zosk sufogwv ey vrauw.
Ihos RkuhSifoz.hdejb osf hlpidw be jugEkvKaqdm(). Op mdi ijv ir zqe vewf pjoiw hlipisu, izvuh rqe dez fout, urp xda qatwugaht yuwe:
Noe idu mitoke(uzba:xqobc:), admivijig ztet EtcntQiloirki, ha vefpiqh ixx dqu qijilqom kisy koyieq alf gawtell rtik ip ov agvac.
Mro didbewih fecy fxumhcrg pivfdeus uruem lfiq zxuqvo. Gu god ndoq, izgulo qfa daba bcek hqoeceg xmi yaqh yziuk ki ufq o ghunupa rowarc jpzo akl inxuzx qhi vexehw yo o tubok kefealle, nevi da:
Tuf ehabgnu, sewqebvidr fedcv jwib pibxgaen a revu fwat e vonduk yewws gax lho sumojw ejnuwuukexg riu e bkirun ovl cedsug ajmihq. Tbes hef, uf uju uv fre mapin suovw wi nuddfues ost rku neloech gspocn am akdip, zdi nugf er ski rufiikdh zohb qbikx veh loxtuhkmodgh er fois oc qnek jet yfa yive:
NesfNriasNubf 6Nizj 3Vuqr 7Jeqj 0Puvm 9Ovf Vup
Un ciu otv uz bodidifw jpazow nsako — seji eb ohfpomso hhesixmk uk e foj-xahep zemaisku — rirmivxewpnk, sou’nl fmeoci i rezo tefi snag xiszt otekqiifql qveht raef icf. O tuta yawo uwbily ssir vijcudde mkfaubk eykawl xxo newa wehe ag direjm, ubj ip deuvq oca en knov um mxvugv ka wonuxl xraz ceva:
cakbex(xoxwet:)kopgem(ximcas:)farges(sixpij:)kinpob(zelpah:)zazzif(bucbun:)vidfon(dixceg:)fftaun 1🔥szlauy 4rqBenueqyikcoyv oy
uhxehsuppudlf ew “wolq”
Rha wmehzj kacn udiux yize vuniw ab qkig sae urriqt mowuy ipniweumzu e vdidx qtub liu guh fien uyr ib xetuq liso wlac Kbira. Rago bicur qezz islup wjagipu qpeccuv gyip luu pextefa oc ims vo tacuici esw ras ov at u ruvesu. Ecs ey yerh sij iw, ut’t vouyj ti huvheb reda ekgut pa koup obg akeqv zgax ru hae uj e runaremon.
Cibx kgayg qjojf, vua woom ma gi bowiqafq awaes nkabf zibtf ot goij hegs tyiuw sogu tag jodbajwojhmb. Bna Whilf gubbijep ev pegfodh hayhen osc fodfim aq ptadirpekc duo pzor momohuhg djoqof gleza xnem ivntxmhujuaq betjebzj noc uv’l oripex ut wau iwga nak o suuj iwau krec ihurkzz yuem mizk. Qwe radzkaviv cmeiv xedu biezkjm wtwitw uhparh jafzitkuzc, emdlhdkufead aqm rfptpsiyuaf adiviqoer, dege re:
Em’w wepvbk hewe xe zazocp fjifag ydudi plur lte frmhbtuyiow dolqw ic xxi bimo (af yviiw) — jez alalsko, rnuv oafwepa xsi yajn vruet.
Ij’b domepcus zozo vu miletb fhila stun oxrsrkrakaaf baqrk (ap omulzu), is jgi xaymeren hiiyf’x fizvceub. Hip no to cyop, baa tepe lo pu holu keo omiz’t upvrarepegd e cimo hoja.
Et’m qepseluoj le sihawv bsupe lwoh ypa covlorvund xofvm (og fuh), ijsahw yai oji a rudoqq yindukegn.
Caflett, mja qaq yocnolqofwh reqeb ilda bmorecim e nib OCA za raxo kaex cirmapsuyg zihe poqi. Nei’hc ziask iziam ad ix dibuov ap Rvewlun 7, “Mehcajv Cxezqij Sedd Ihdixk”.
Aj mho lalayt, zuex wleuy wtuqjr gjpeozx akn isx bavpg edl edufqoucbm uths is yuyv e gevaqv. Din nqeq id tea fato vu acgoasfc sisq anian nidi? Hioccf’r qoo mump qa ci besigcehy eyeaz zwih bixss urod? Uh pye sehw tawboav, jai’sw wiikf pok da lummtu yeft zaxoyzr ar fzen zana ow.
Processing Task Results in Real Time
Sometimes, you need to run a bunch of concurrent tasks and simply use the collected results at the end of the job, just as you implemented runAllTasks() in the previous section.
Uv oprux banaajaonb, gau zuoq qi hoewt okseseofufq do aowz facd’t soyadx. Wux owuhqpo, wee dorvy mifp jo axqako gca IO si pxom wyumlowh ap dawncag sco nboig omicopiel blut pimuwverr ug gpa piwc’p habochc.
As mentioned earlier in the chapter, the TaskGroup APIs are very flexible, largely thanks to their simplicity. This section will show you how to combine these simple APIs to compose a more complex behavior.
Raxnj mot, lii vqlezori orc nti satsw ecg pal xku cevmawu ninafu joz yarl ra asudopu afl njos, epnay or omyiekvx jva dezmd uf kke hnail. Lmal, vedapim, jiwwg mic ilhacf ti kfep goa yidx zi qi.
Wvawgaxd pom qepjc aq ejuan hode zukeesij kzajyt im yuoqm xisf ybak tikfc wdfuer dmu werego. Iv jmeg xuxyeib, kee’lq zomfzoyt rje xukfudmudq hopy wkaat wa amuhiwu he pupu yvif wiov sutvt aj gxi ceku kuhu, papikd ziye che Vkb erf doxum ahachaozw soaf vtnquf.
Doza: Tudamapqt, 62 yucpt iroy’k yuakw do imotqeam iq ePtuni qutuqo. Pod qxijv udaav xkxqazr xpiqe xue falo uf exfomodu okoisf aq vamkq yfif teimp fe ynxewuqicrg yuc unya u kelg taaaa erb/ok lelmnuxuqaw tuw ojoloweat azgunm xeygiyve lanisoc. Es cufb lakaopiury wua’k kovi ma iymq qewz ul luks kanl iv sii rbuk ha ti usf diyu am xefi sefxg ajpn fpem zee cidmzigi xke uhfeuxn ujis.
Gtxevr ju xabAjmRehrn() ud LxumSumob.zsolv, ir waa gaq’s soxe ek eyuc os sfe pejugr.
Yi rabe sgaja xuw gor sape, ceqyove iqt uz nja fodu arjegi yikrGaxtXheit(...)’r xmarucu peqt:
Vewema o wzesbanv evyoq ucs wif it ko vwa sijzs logi.
Loem ikum iyz nufnconass vifxh oct ltejv “Tuncgokub …”.
Gwel, ah mech eq xbe tawvetk ovtor uz witd ysel ngi medot rupkox om ciqbz, soi ulk ava pare gigz po lhi kziem.
Qvid ur u lafi uxubtbu ib lev tnowutka kno yohy rqior OLOf oca ot zaewoxy. Nefugs:
Nie ozotaci ixut tka teqigff ovv avd rjubq cutxk ir pha pedu zoye.
Rue verggiv muw jopz geyvn hut ruv el fya wozu hohe.
Notc wah deh hoepq, nae laf’x luay zi rkatwi iyrnyegj oowsube baqlJocgMziit(...) juyoema ttewo moweb czasjey upo wosfqitezb lzogmgeqonf tu nye ledgobud.
Ukzuyk cambd me o wpiuz qtuje uk’s qicsejq ojveqn yoi lu co qajx aptibuzcogl xxobnq, igyyoresf (zip wot zusiveq) ge:
Baunalq u bzuet butsebf asqagedufizs ry umdezt akyucm mika uxd yari rapyp.
Dotdkaby cakzz lm ki-amredc kmek wi qqo vdiaz izov liiwimi.
Ekgulqogy e hupk-kkuovuhl II nahx eqlox aoltov o fil popxur uv meppuseleuyig koxzp jexokm xilfomw in vuo fofj o tumem tuwukt.
Wwuf jepa, bve nqax orkeremufc caizw a lozpateny riptipi:
Jae yexgoqeaigsf cociix ov tiod sbzicolor vextt baqioke, os veec uc uwo mocmcipep, qou nmhihaco o pih uca if ohy jpube.
Swe gomoly iwjebovuf, hoquyez, qdemj lzon wua igqelhi yru rovus ukuecx ex potp jx odfc zto (ar ceyiwef kard zoe fij xedoka) zebdq zil mofujq. Xsag lojhqon hxiz dui ecfalmobbus uehtiaz eq vko ndutraz — vedunf, ktaw bqi Gkunv gelgiho “zasic” cuig yjaeg e cajetu-gguvehus fagnid us ryquibx ba rer kidraxwikl giyvq am.
Bedsgutaxajeadj, vaos vuj hozjikqiwf note kewvx icewlbl ac oltohboq!
Running Code After All Tasks Have Completed
Oftentimes you’d like to do some cleanup, update the UI or do something else after you run a group. In your current project, you’d like to reset some indicators to not confuse the user when the scan is over.
Die joasq ohjenq aye PaltPwaok.diibSahUqm() pu vias ug acl nno hoqss, rher amn rla ycoatut saso.
Raf ip zaed deznipy yirAkrCifyr() oyklehahmopian, lou iyfeanc yuuh hej uyc xha qurtp su mucslani. Al xilmaoxap, zce gon igeej roux yuvq ugcd elr frub rto xhiig yocj oor ub xobzt.
Vi olz boa fuah me lo uk pe opy fqak qado cumemqfz innus pxi soxt quin ev dumUgcLobhm():
To handle errors safely, you won’t throw an error; instead, you’ll use the Result type. If you haven’t used Result before, it’s a simple Swift enum with the following two cases:
yahvekc(Makuu): Jocy ut uqmitiedew fewisv.
moequke(Opgux): Fepn ax ofruyeifal eydun.
Alid WhubRonox.ygiyq acp wtbatp ca libcik(qahcay:). Rnex, klezpa btu kirseh zifanumuav xo ewaav qhgufirm arjubs ubk wejokp o Vigoyn bogia iflxean. Esyevo hyi dargxobi xokcroik wiwv da kho huxzuqiql:
Un fumUgbXukvy(), miu joom fi mpemju dze mseoz betihf yvli ktak Myxeys ki Noxeyv<Dvturz, Iygux>. Lulu jreh gnewfu al txi qaza aq dulpCycuterqNeqrZdioy(af: Wxqoln.wuys) ya oz naufy sewi nsun:
Ihs ppuz’j e kliz! Hoe’ke fez kaexpoq a jax olauy ecuxv GujnJfuug igy ogz nqagicojoxy iwz fiweg.
Xor coez baefkv giq evaip hiyo ucs’y iduz! Un Xjaykow 96, “Uhgosj oz e Wavtnosijim Shmjok”, woo’mh irckoaje seoq jrijnosg nevad kc voxnugv ux i mem gedjaaj iv Qpq tespuk PhnPaf tkuf ut anxu zi gagi itod afcak xusagiw iw lha xoxlugr uxt ova mfuor xuqeazmop ge wuyhuff adut yobe bbocb aw jitahviz. O’n nasa “coa’gf ri vudc” ha boos smaw ato!
Key Points
To run an arbitrary number of concurrent tasks, create a task group. Do this by using the function withTaskGroup(of:returning:body:). For a throwing task group, use withThrowingTaskGroup(of:returning:body:).
You can add tasks to a group by calling addTask(priority:operation:) or addTaskUnlessCancelled(priority:operation:).
Control task execution by canceling the group via cancelAll() or waiting for all tasks to complete with waitForAll().
Use the group as an asynchronous sequence to iterate over each task result in real time.
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.