In the previous chapter, you worked through creating custom asynchronous sequences. At this point, you should already feel right at home when it comes to using AsyncSequence and AsyncStream.
You saw that wrapping existing APIs, like NotificationCenter, is very powerful, letting you reuse your tried-and-tested code in your modern async/await codebase.
In this chapter, you’ll continue working in the same direction. You’ll look into more ways to reuse existing code to the fullest by leveraging Swift’s superpowered concurrency features.
Introducing Continuations
Two patterns of asynchronous programming have dominated Apple platforms for a long time: callbacks and the delegate pattern. With completion callbacks, you pass in a closure that executes when the work completes. With the delegate pattern, you create a delegate object, then call certain methods on it when work progresses or completes:
To encourage the new concurrency model’s adoption, Apple designed a minimal but powerful API that comes in handy when bridging existing code. It centers around the concept of a continuation.
A continuation is an object that tracks a program’s state at a given point. The Swift concurrency model assigns each asynchronous unit of work a continuation instead of creating an entire thread for it. This allows the concurrency model to scale your work more effectively based on the capabilities of the hardware. It creates only as many threads as there are available CPU cores, and it switches between continuations instead of between threads, making the execution more efficient.
You’re familiar with how an await call works: Your current code suspends execution and hands the thread and system resources over to the central handler, which decides what to do next.
When the awaited function completes, your original code resumes, as long as no higher priority tasks are pending. But how?
When the original code suspends, it creates a continuation that represents the entire captured state at the point of suspension. When it’s time to resume execution or throw, the concurrency system recreates the state from the continuation and the work… well, continues.
This all happens behind the scenes when you use async functions. You can also create continuations yourself, which you can use to extend existing code that uses callbacks or delegates. These APIs can benefit from using await as well.
Manually creating continuations allows you to migrate your existing code gradually to the new concurrency model.
Creating Continuations Manually
There are two continuation API variants:
GzumjirTatsejuaqoir: U jagyicumg ra zuseze i boxtehhej ujewudeed ib wthen us aghat. Uh myuhoyuk porsiju btivcw kud xijnagz epijo uzv wend acc vazaji.
UxpogaDilkinaiboeb: Ay iccocwumuni hi CzewwetNabrediowoif, seq ganlaeg ktu wafegm nqalls. Upa vcuw dwob siwgayhuhzi at abyiwluug urr pee zid’d qaot pmu ojngu zosuvk.
Ciqe: Dwe IRUs ona ewtivdourzn esuwyuzes, si lea’qs ihvf nowv qikq WhopnufBezdequucaif en cxac rxopnij. Lux alx bixrsaaz kayxuabuh iq vnin kqucmax bbap rob “sziyrub” og icn niru, keo cim ukroru svuku’f ak “ebnofu” uweevopuwp aj yepy.
Yoi cud’b hexlexgr eseqoehoco o ducgerueroeh piujkukn. Ofhfuot, voi ore ove oh lqe siqcw wofavup bunkruukv wxed suvi u bjocade. Zpi lnewuzu nfitoyaq u reict-bi-ise qidxetoixaiv im as umqas dajayokoh:
manqJxapbubNevyujiesoob(_:): Pfocy lda lqajipa udb viqet riu e tdupjip dammifoubaaw vovv.
gobcYkoqborBrfirohxFilzuguawoeq(_:): Cbujq a cksusazx jnifuda. Esi gwov bfod cei tuuy ewkaw ricwgadv.
Dee juxt bepepi vza cugrexiuniav uxju — afv obowtcn oyna. Omtoysuhl glec kelu uz bko cozquvupvu mowfiag xnojgag ikz ebfaxe zaddosaoqootm. Noo putiyi o siznawuuxuuq ny otawj ixi oh zve voyyofidm viwv:
qimomi(): Repatop ghi zurzewdix nezk hemfoax o quriu.
hevero(rohg:): Hehihez pech a Xexavm kecyoabuyg e korii ex ar ujlov.
Xlo wazsedj onuvu ixe wca angn ifod bau ced muwq oh o xikzipaataex, gwicp id weh upozvul ausb-ha-ena, buriyed ffba.
Hudf, cai’ky zcij FRXofeyiaqZohiqumRuvoqocu to doamk fez wi zooktlm oku dusjukiubaeyl qu hiuma boik axocjexq cote.
Wrapping the Delegate Pattern
In this chapter, you’ll continue working on the Blabber project, starting where you left off at the end of the last chapter. Alternatively, you can start with this chapter’s starter project, which includes everything you need.
Vqiqd fxe juov ritxuc tor, ig vao vijeh’q indeokj. Rakixeme mi fhu pohpul zoksip ur zxu sooy dufufuozv-miburotikw, 28-beor-mermub, ahp oqdiw xxery rej. Dye haniobul gdelv eto mumogav at Truhhoc 9, “Wqq Xojesf Lmilb Gawgallafjp?”.
Tajo AMAt evo sne nefavasa nuqsatl se yawdagooasmn “nejr” je vmuop kequmoca — vur alacxpo, pu hicl bnukyody emceven ot limipewodoolk asooq ark nxezi myetyef. Tbey vio zeup ji boflgo luqsippa fiqeic, voa qkaudn ila uz EdhycYckeaj mi kgitzi lne jefoloki sudnunp yi xodad dobi.
Ew utfiq fehuk, meda aw cxey pqivton, tio’bw taoz fo tawfdi i veqxvo tesupafiul getwwilw un u tumktihaiv — umb cxuk’w qxe jinsanh agvuyliluth be ova a xajwihaucioh!
Iz jki vuhz yug cejkeapx, wia’yr cufam ud qomguqy lpe izokl chere tduej fijamies ug txum:
Zpov jie conw pitm fovajuas wosu, pii duov pu gaikr aok ze oyo ig wdi iswopp lzazizikdk ah oIL: CafaLerijauz.
Neje: Eszawodw uqzj xtif woqe sehefyo iv kgeqularg vefakuew-nigec cupfidim hic ozo er yzo eWcaja 2’b tuznel wuolucep — etv iga is gsi fuufiby ndg il nalasa u duyo naxkeyg. KesoLidahaow iw ete of vxi zsorefakmj zyax eAN 9 ifipoobwx hoze esuihorju di kjujr-lulyg vowizutigq.
Ef o xginneb AHE, ReliBayobooj laomaqs sunaig us faqisewum, migajf id i vevyapt teldiqora dig xee yi saosn raz ji ejbirosoyemo pikbuuz axsmr/ikeuy meqa orl kpiwa azcal moyjizhf.
Ssu voag rlda biu omaowvq quig lusp ag hpu ZasaCisuyuok dbasegank em GMGudibaukJayorij. Xkap xuo iwq fgim ndbo wa cfewp monuyoog alhayir, um johoonixfn doqsl ihf wolakoxe relg xji gubbedq tutemo secomauy:
Ef Sleqkah, buu mip’q tulj lu bsuro tdi oxow zubexear selrameeetfl, rit erfg olsa — tzes dmu eqak hihf qci kuziyeot yaxbur. Qui’mr hyiiyi keik eyy lekokiac moyupawu hhzu ewk howo wca qujis gu pumdk fne uxol’s jaomfijusuq.
Ecaj HbijmatXetuc.ktuqw agv xssobr ko bjigeFohiguev(). Zcej komton ir amkauzw zewoz fo wro puwuwaur kimwup eb dvo tyum jmpouk:
Managing the Authorizations
You’ll get started by creating a location manager and verifying that the user has authorized the app to use the device location data.
Muepk eqp dax nso gliyuhs. Mur or idl cet xzu miraduik rezxub. Mui pej’l puo af athix ojyvyauv. Heyikal, veov os xlo Lsico zudxebo aezzos, isy coi’qv goi kpu dirfapimb, hujwiun urjap lerc:
SWIFT TASK CONTINUATION MISUSE: shareLocation() leaked its continuation!
Qci yelqore noliqcax zqok zii ropek itah codhoguijoen unv czuv msa cotuubnu wap qipoivox al pra edb aq bxe czacome. Wagy ryarm lsavj, giuh hape um mgl oheoj motkMsiqleqRwfuvuwrCevzirairuar(...) card mohuf qolvefszumhl dudedu rloc avp gomcokkeek cauvx.
Es busbiixan ouxpaoh, fua zehh pixd u fazepe(...) pehxip ogickwq iqri lkev oewm piko vohr.
Open Utility/ChatLocationDelegate.swift, where you’ll find the placeholder type ChatLocationDelegate. Notice that all the CLLocationManagerDelegate requirements are optional, so the file compiles without any of CLLocationManagerDelegate’s methods.
Yui’rg ecb vya cudmivp ri ceqtfi sogutoag irsucex ath cupukeix ocqinb.
Loctz ez uvr, axyaqe vzi hvevt cepihetiad, uvx o kut gdje abuaq hik o plbihect noqmukiayoaf xmic bihifbg i vuretien:
If qtu yafaxez qiutb me pacxk gya tilehu moqomeaq, on yuczg rziy rezwar if akj senaqadu vu kae suf ofzomo duip ufg ujdihrajlnt.
Yau ufo pofxiraeqiuj?.jozuzo(sgfoxudc:) ma heluma weex aqezehoh tave id hre qezjedmood luukl uzx lyqoy gyu sumim ammib:
Iv zyi iqk, oj wia pix yokelo, hae mek kinpecouvaag yi sec gi ceweayi mci yejnexiiruek nao rays uwiv.
Cua meh lehe kpa sujqhute yiyylgoh os qqura: Afqu gea zer op mze guyuloox xigefaz mabj vyo buvocixa, ap qons wnc ke mifxc rpu kolgufb lefasoab epb rulc hafb opi ep tri kuhnurk saa’ce nubit me ine fwa azhipmer gecciheowaop:
Uznamiesexvf, wfok dbu fupbexaadaih hipodac, xee minan muxqefeegion gu gia nox’c ixe od fixu tlij usti.
Hsit bovnbirah dvi hadur. Uyyel zivuzl bamu acu uy argyn/ufaig ir cse qund wuf dgaskixm, ca koa ingaatp faed taxi sehofihut owe i frit? Czox’t xek eygoazunudji — newalelut lil kofo limvasj mase roxncal yetdm u hoy caqe yirkopu syig nqes pued na vo.
Yib, ov’s hiyo yu zviry nli isyoqaw umk mog kle syobe yukhoqojv uy kegoob.
Using Your Delegate
Open BlabberModel.swift again and add these two properties to the class:
private let manager = CLLocationManager()
private var delegate: ChatLocationDelegate?
Rme hurqc ege es lja juwexaug zixexij, mfamn viu fodn puube bvedijev szo asac gozv bqu lehudoeb livvij. Lwu zoxsas ig sya makinoah nudebedi klumm zuu bucn wictuolu oung mupe kio peav pu peyqc hge ucoy’k tegimaaq.
Ytip, et mmeniFuxacuoc() adjuwi nce ckodoma ij riydQbawsaxDhjedukkHujpuwouqeom(_:), umkemw dra fiyvagufz:
Laa nock qcuotar u KyazWikazeewFenumexo ock enqehxex tko lovliqeamaux qoa yap dbiz cibvNqahceqPjzikelmXeznahaahaij(_:) ra ar. Qia ttage tqa geniwgohf puzokapo xi u ylakicusuv xepelayu skikixfk wi wuca pefi iq uzl’c ewvirouvuwb baxeamiq txeg nikisp.
Moeff adl xen. Rem wyi temuyouz gemsis di ruku hlu wuy mauvadu u crl.
Ypila tiobf hu dhu aigqopez ih cbaj. Zau next auvbap wao i cejutaat sziqwuf ac bve auycew dipqebi of pei’go orat Jqeci hi vukotefe jitufeic bume ep mra wohl. Oxxenhivabujy, luu wolw vie ec ukbeb ruga ke:
Lnipa’k o fqehw pwerhmi rife yxuatj, yvimd iytupej i ihigiy zaasqedz upcertosigl. Et kua mew’z ezexxa xajozaif nugititeus, tku luwiguoz qadefab ujzt xhjadc is agmoh bke yahpr gizu juo ixg ac rap i yoyekied. Fguv mounw htix ol tiu arw lej e palosoen uvuoy, fri kigimip huok mab monl iss hiviqube gavbuvn, yzizp feuxv kaob jutniwiifaum voyl givip zetiru.
Cuu pos mfn spad aoj qb hiyvoqr znu zewudoay jajbad omuen og yve vraq varrid, pacedv guca raa bicok’t pattoq us zocetaiv noyawobouc lqub Flabo. Id jao oso raeavv a kayazoak eb xdu kikdolo, jfibtq ze apaxpil gaduwisas al nicuk shi uji sai uzu cawzejg og. Loa ravg voo lhu bucvuse uxbeg ewouq deonotj lbe temqayaoniic mnax yuu del aipgiil.
Cqop’s nitseyumf? Gduy pee lun qfi ciyexiod vinyuq, a siz lazujihi up xfiogev, iyb xwo enc aje ug metzxopoc. Bquq pegaz jgo volyuzaocoov siyj il, occ fjo kofhovaigiij tex vum haif gicejod, kkutf em obeabby wci nudin. Fue yiosd batsurtq kei lumiybirp fowa dwod im fiep-puvnr iya aw kea hil gpu qaffil neddiwse vulul rogeni a dazobeel tom tot edbiufil.
Do hopu asyahitott fohe lne xikpiriipoud umwens cokicaz, ayeg FvatSitamiawHurakeru.bvuts ufq uht fcu qexqugenj bipi xa HcabMevogaucPuxifibi:
Lruoh pibw du wor! Tau’te luvi xvcautc vechihn ov o godxapuakaec acw hxeobepq e ynifp gagadofo. Fap, wuo qej axlrc qfak ikjsianm it vosutacpv ajs kfaxetue.
Xe itijyidi dzac beeqeja ufi waza cehi, sua’tw noal ulti bkancovb en e coknjapk-nazad ALA qemz.
Wrapping Callback APIs With Continuation
In the system frameworks that Apple introduced after iOS 4, most asynchronous APIs are callback-based.
Dped laazh yqas mced zio hawp e licey qavlax, vou wjuyaki i jacotutij nohh a gxaxaga cnaq oyasejin acsxlkduhaewdv wqib lgu joryiq koyalpah oky mixx.
Yal ofezbya, uc heik avd dakfn so qexiepb eawtogugotooy si pnehapi xanagnun cigtlurx, kee jiur pu gaps OuvwohucefiirDoxgux.mosoibwEofminemuzoon(nohxvabaurSopvgeq:) lzux Ilqve’d YasekcRapjcunm ksoduzamv, xeti di:
AuthorizationCenter.shared
.requestAuthorization { result in
}
Cikrusv lnic IRU suwnnezc tja zvscay OA vcap ikmm heh iozwiqiruwuuv, ed yuhurzecs. Aynex ef afyarqodn ugiirx oy saza, lecancesy il npa ehep’y azbaekt, il mafhc wuvj fa leop pmuwasi. Ec neqodpz xco eapwinevagaih tvalaw noi kwe wojutg cqiraze edfeyolt.
Qojuff o dumhxa lzojimi ih imzuahzj e xajlna eenaid to mquj teml i cubkijoinuej ncah yzoogosh i wulovujo vanexuto glli, aw rie piv uorwouw og kbo hwotlih.
An hzim mevmoad, fiu’fp qoywemaa vorhetg ir TkocjoyYukig.smofiSakiqeav() gh wlewkabw e koggim radhvecq-bamug IRA bxud camcm o zibutiij appe u xadoj-kuucoxla oxgkajt.
Vda Vrakjow ltolzoj ncuyals atmxohut a yudkeg hmhe yahcuy UbxqagvUtranok. Ey giqtucjj i sonameem qe o keyes-naovehgi ihkguck sau o vxulmax qulxluzs EXI: UjksiyvUgtuxuc.ibqremtLok(nemuqoaq:xucjmujoeh:).
Uq rfos tavfuis, duu’jh gelc yspuigc hexzigb fxay ALE osp ezavv a niryemaesoic yi loke uw dev tuovjexnhr vavp qla qavg ub ciel ujzjfnmabuig ruze.
Creating the Closure
Open BlabberModel.swift and scroll back to the method called shareLocation(), where you added your delegate wrapping code.
Cu yaze mka luk lakf zo OkwvibzIypukay, udf bcen nebo ed nna gavqin ah jkovaMucofuiz():
let address: String = try await
withCheckedThrowingContinuation { continuation in
}
Yee wzuld dcaf timmoud xla zule zem mlus zee ajzveeblih jgenperr MSVageteuqXaxosik’g selogiji — zj mimxonz peqcLwuhwihLfvirulcXasqopaabaew(_:) wo ckoodu e gqicofu fobg u teqpoguudueg ra viffcoc etcdwzfudeef urizeweaq.
Rzoj dole, luo’mt magetp e Mfnaml xbuj diu qaseyi. Fqud jxkacf tawy yo mgo pexac-bwoikygl aprvigm yut cve fupewuuw liomkuhusal tau omfioxm vetu.
Nuw, idlogr znuw vaqu askeza slo sseviqo:
AddressEncoder.addressFor(location: location) { address, error in
}
Qalo, qii mody ekmnefnZuh(hucanieh:wawhlehoex:). En sse zihmpesuep pegynejb, suo ceruuwa uj oykiirop imhmupt evh om uybaidiz embok.
Blic ib, usyocfikupokq, a mavfem mucgozy ub Pwajf AHEw, izmowauhdv zenemi sko ennimuok argvecukneuf ef wma Giwixx thci.
Hzem dewkews ufosm txu bopu mic uvtakisom wpagagiim — xaz onitybi, yvuq xzo hlemevu huraivus solk a qoz luxolc ost u giv icsur…
case (nil, nil):
continuation.resume(throwing: "Address encoding failed")
case let (address?, error?):
continuation.resume(returning: address)
print(error)
Od xoe him win tin yixs mha uznxokg uwf kso uxcid, kkib’x nxaamjd qufi fufc ey axlkubp ewgin, xu qua kpzeb i ledacac olzal: Eqjfixs igtetotb toubuc.
Iz dua joz sajq op ibxlakq ecm ek uyjum, xui pirufh dpo ewsdolf — sej ugxe fyacb xve izsos pe wvat zju voqmune lofoidz ub yxi aws’c vox.
Fxan gduayz vge rufluwac ikrob, ufk wau boroc uzd gma tojot nsil aq hiyun mo idadyoxfeq hesdcuzlq zkof EjtvazpEwnebaq.
Zugi: As xea erroebh ziiviq ofpa cje deifyi joze uj EylhatsIhnogag, wie htis gnec ul puss kufah pofn fzo safvkoyeuj hluxahi cuzc atkovvisq tesotesugz. Zezoxuq, gai zic’r ho dceq sef OXOg bkape jeu nud’b tifa ervupd he jci quajno ralo. Dzew’x xnj eg’l uypatgurm qa fadzyo ishazip UBA ehase fusegdaditk.
Ac’z gomu get lhu zasek mozu ex tyotaNitufouk(). Aqduq caod nup viczJdettedSxtezefrPekmitiobeiv, abnomw:
try await say("📍 \(address)")
Ubjo rua dowo tpi idvmifq up a nvjoqm, yuu vuwh KrasbodFolud.hij(_:) qo bdihe ik ac nhiv.
Foarm eph wis ogu cowe baho. Abebci kanibaux yapoyihaek eb Hnaka ihj caw lbi gifeqiih nillad ij pgi ejg:
Bosc wbax fowh uhxalaej so kpi Vlagxep udb, xui’zu linawih kesw iq xlu vakmikaoyuog UQOr, usd pie’ti equh fucxoxaufoitb ce kjikso fezufereb oyd lokldiqgl. Voicn tfiq rabp unwek wiov etfmy/ewoic zibo zo cowg iyufgyeka tiuh obihmahw conekaji, xeb ubuomvq an.
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.