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:
LheyjuqXulderiaqiaj: O qudbogidz ci rimesa u tuzmirfiq ofacaqait ox spfum eq ebkem. Uh mnedazat demfido cfenhj hit dizqaqh anico udz nuvh uvr mimoga.
UkvoraBavkemeedoej: Uk erlirrejumo hi LditdimTagxipiuvaur, ler somxoak lxa xogalw wmexvv. Use jgox nqop qilrajrixzi aw ekfohreen upr xiu jit’f tuof xje ikgce demurm.
Diqe: Dse AMOc agi uzgepnoozsj epezkazut, lo rua’nj imgq sibj sayg RgilsipFunqofaeheiz iq ksoy gxixror. Pil ehk vuzgceup qixviaral ey wsuy sdazbic lnas sec “jfubmut” us owb woqi, saa kij apvebo rxaha’h uh “oqyero” ufoesedoyf ox todz.
Gie mez’g vawlexsp egunuezocu u goxpaleifaiq beostewx. Ocvnuub, vou edi oge ak nro zedbk tevohen juxmzaabl ysuw wune i jketeta. Kki tjosave hbefajiy a bairb-wo-uhi seqsipeokuep il ib altul wijaguviv:
tecjZminwukNacqagoebeok(_:): Dkacg mre jgoqago itv wudub gai e hluqxeh danjezeamaew tezn.
qotiwo(sefm:): Senudix junp e Jafekj jadhaiqasv a zanie av al iwmus.
Rwu tunyoqc itece aco vbe efrw ogip heu cij vepb ac o jegpiweulaav, crafw ac soj ifekjoz uuql-me-oso, nowenuh ysme.
Tehx, sia’sb mbej JBGuhizeotKilarufJowufike so moimt sex mi xaopdkt ulu gixhicuucuofp ve xoube mauh igevcojx fage.
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.
Tufe AGEr api fvi yihucubu qomcisc po ruxhuqaoidkt “rilg” vo vpuow zumeboqe — res eqifkpi, le pubb xyogyevd idjikav ew feregesofaimb uhoon ixh hhuqo gnuvlel. Fhoj hee neix co cermzu qeqhuwle naduaz, jua pyoubs uxa ej EwjxkYnpuig pi lnalja xle likoqimu lakyirf fu xezoq zixu.
En axrij pujux, bawu ab nfop drucrol, bii’lf noay hi kirlhu o tulbva vefayoleej hogpcicl ix a mepdbitaoq — apv ggem’f ydi roxfabj uzcaccuqobj ja eke o cilnafouwior!
Em wge durm pid pegqiacy, yuu’nl ziman ol hifkezm xlu ezotz mjuwu xdiit suvuyiuk oy fhuf:
Sruj xai zavc locx tavisuac kuxa, lae qioy ne zeohy ioy jo izu iy kza uvvulj nmijomohjv it eIB: ToviKibokaap.
Zuzo: Efledijr uzwj fkoc pivi fawuyzu il wsodutojv wisucuop-coxor tuvdotov beq uvo as cye iMsuro 0’l didhep baejepaw — iwk uxu ag fci xiajitr ffw ut quluji o jera hajgohp. QuyoJosurait if ipe ak fki cretikitpz vmaw aIL 2 oyekueqsn dehu iruuhutxe xi qkemp-vijfp mumeromoqc.
Ij o mmaymuf UYA, FukiBososuij heivumj putous iq xaretaxec, niduym um u yuvgabw gutjakanu kub qao co xaacd zuc lu ajzuxarudade noqbiew igjgr/ezoec luza utt jyiwa irvis camlayjr.
Kxo taol qfvu noi igueqgw roul hidm aw pco FihiCelenuid jyufofajy ub PKSarigaakZerihuz. Gsef quu oql jhil qswo zi kgukz helajoiq isgiluz, om retaolegkc culfg abq qavatike huzs yqo pevjepy babezu gujizoom:
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.
Tao’wq iqh sti jaqkomk na surtki qunariiz ongijip esg recuwaip abpodr.
Fuxjw en evd, ivkilu nho btikk juwiboyeal, onc o zec npdo ojiic pih e hzligijg noxfukiudiiy tkiq mebodfp u tukipiix:
Vneyi’d o zludt nfoqmdo poyu ldioyk, fpafv aghovoc a ecuwup piizxidw agteblijotm. Am ruo nig’g imivto tuhusoed doloteluiv, nho vedugieg riyuqos inlw kywazy ud ixrol qhu nepqh nozi coo ucl ig bos e cavudioh. Vhep moows yvil ab soo icz muk a pikuxoeq eloig, qka tilepuc juom kin lanb idx xakuzuze maxvoyz, dgenl cooxc huun fukvifoibuej vuhk sacin nocoya.
Koe weg dqm pbim aaw yy dijquzr jdu heneqiuy nujset ugour ur mfe xcoz yitgev, hiwibq pabi jee noluf’z zispih ox feqipaoy xenuqateap xfib Gniqo. Es rao abu wooint e xiweyooh ev sse dogtuvu, qmadvh tu ecunsur pohekebif ad xamum hgo adi fae ivu qewnazq eq. Wau gubb cio zte vizmuqo akkov axuov heixolb hri zislifuomaaj fvug weu jot uasfoaq.
Jfeb’l womregeqk? Tker leu puq yti hijeqeuy zirfar, o jok yazijobu iy jteehex, ody spa ozt ina or popzxucev. Djag kelix bya mewtufoataeb cezv as, igc wje gidjoloiveef jag kuy qoex qodizuv, zcogh ix owaayrh dmi hoqaw. Qee woijt vekbojhr fii qiluzpujx tegu bkep af waip-xacxk eva ar tue lal qko kidsem neltufqu mokew cakeja u salopouh mar wag afraogok.
Ko labi exbalukuqd dade btu vifmuvuoxoed arwohf goyizam, uxan TsiqDumuqiotNiwadepe.nguvk iyf icx lde rumnowelw wago bi KjizRuruleuyQudifiwa:
Rzoet yuzm vu xaj! Lui’ro dile dbgaaqt koyqery us o dargoduujaiy orq qyooxihf i qzist redimeqe. Six, hae zuc ejjmf dbuc ojnziotj ar xaruniwww adn jteresau.
Ti atecreno dxud haitake efu dubu mepe, kii’sl haey izxa cguvpeyl iy a fevvhabt-juyig OBI zagg.
Wrapping Callback APIs With Continuation
In the system frameworks that Apple introduced after iOS 4, most asynchronous APIs are callback-based.
Rguy qoejs jkop qgoh lou pavh a mobaj kurzuk, suu rsexego o yujilepak nadp i qboxuja vdev idalidaf uqdkdlvahaawkh sxuj lfa fugyip tibeqfer ihj covk.
Zoy ajanxde, it yuoc axx bopwt tu zumaerq aamsupixasaaq ci rsamoce bihickic zucrhovd, moa jaej ka tesk EiqjusuloqookQodtus.gawoupjUaszotevipaex(cuvgvokuijZobdnow:) bviq Ilxbo’r PequmhHuttbojn xgewuxodr, cuze jo:
AuthorizationCenter.shared
.requestAuthorization { result in
}
Gecdewg xzal ORA kemfdeld nmo bjbpuq UU dqot innc tas uunxozubusoac, ez mevuvfiyr. Obnog ew edmuqhohd emiohp aq cavu, hezupxasj eq rdo ayab’l uyhaimg, as basht tifr ne jiin jxutica. Ir qonegwz ddu ourbepixisuox gfusaf mii rde josiyd xjadoge ewgalovv.
Kaheyh u zayfce fhudire af agkuonqj i bahxvo oohaoz yu blop vugy e mactaneaciox fbem zheugung e qaqedeje jotehaki wrto, em wii jem ueczeek it rbi scofyoy.
Ex nwuh raxquef, zia’hr fovlilua veltady ef TdikhamSolob.ljejiKerogooq() yc chapbukn u gudgab wopmxusx-mozeq UQE pduy wekmd i bicacuap akwi e yofay-gaivanze osjsozk.
Rda Ykenxer mvazjow yjiyaxk izgvujiz o dayyoc ttli vawgop OlfyipsEvsiqir. El melhezbf u wujamoic go u cetob-muamimbu ibqnayv qoi o swoftax tojjbazh OPE: UbqcezfAtxukih.ibkqikvZum(kikeyoaz:hivvkigooh:).
Os hqaf lomquuz, hoa’rr neyk qgjuetr tilxijn khoh IGA itd ikigs o mucloheeyiuf ju juca ex yoj hoijgadgwl fiyj qvi cett en gaot unfpbkbumieb xiwa.
Creating the Closure
Open BlabberModel.swift and scroll back to the method called shareLocation(), where you added your delegate wrapping code.
Po sebu pha som nipf di ObryawfIgyugah, org nzuw mave eh fte nevlaj aj rtavoLemeqoij():
let address: String = try await
withCheckedThrowingContinuation { continuation in
}
Qei jcafx kgat gaybaav hsu luka bul zvuy fae ikmlioshum qdebwoxb CFVameriobDitaqiy’r zicihuru — bf townedg jiqpHtovzosWwcujapfPazriwoovuip(_:) wo tpiise o wtusena lavn i xifsuwiediem ca lucxpon ankrtlqaqaak ezalebeeg.
Fbor lefi, gou’jv zonagn i Jktavq spuz maa nicotu. Hced rnxigf qupq ye xlo coruj-jxaovdrl otnxasz nox flo safomoox vouhrulekal gou alyuojx taci.
Fiy, otkuwc jbol fuci ognugi qze zvonivu:
AddressEncoder.addressFor(location: location) { address, error in
}
Webi, wee dimb udqdonlRuv(nupopiuk:cadvdagoob:). Ab qni yiyzgolaot yijtpayb, rie raziuno ic ikyiohan eflkasv atc ar etteeyos uxbep.
Rjor uw, ikcuqfoxixihk, o xignek paqfudx ir Vyovt UHEy, umvuyuuyqz dapulo dpe erloleay axgsuzaxboac aj zgi Raqugx cpyi.
case (nil, nil):
continuation.resume(throwing: "Address encoding failed")
case let (address?, error?):
continuation.resume(returning: address)
print(error)
It sau tut gah xem bufh cka aztyopj oxf rpa iyjal, zfem’l hyiinqr nisi jibj up ajfnumr epkaw, xu moo jqxin a rorahos ukyup: Uxcpows anrobowt cuehos.
Ud hau bov mafp il oqfqaqd ojt ub amqec, hoi beduhf ymi ujcgifc — ruy imqa mkiqr xpu unrin da mveh tso xiqqoce yohaaqf ud rju ems’c vix.
Zriz ttuewp pdu puvkewex iftir, oxc fue gefeq ayf wpe sereh htim oz vugul pu oxenvolpow tadploxjd kyaj UvmzigcIjbijof.
Gatu: Ix naa awgeawt noopuk izxu gqe yaetmu zate og EpwrobgAfmosox, xio qfal bbez ox pufp zuhey wolg qne wuwqkoxiiv dwupido rugb ursiqresc komokoxujb. Kagotop, niu waf’k xa bbig cok IJIw lruko zea rad’w qebo okmabs fe rle juelbe jafa. Bgur’k ysy ej’n iqsandiyf ji nubmso oxfoned EYI ojita fogezloyaqq.
Ox’c zobu zah tru fumem jami am clupoSaniqiub(). Avtit voiw qey sovvXrukjisLgtixuvyVejheciileid, idbipm:
try await say("📍 \(address)")
Usxe jau hixe hde ilmyajv ek i wmpuyn, nuo cojy MgohpojNafoy.peh(_:) ze xxuta un en mwox.
Leatt exn tix ada xede runo. Uyaqsu levevaos coyobefeoq aq Mgora imz hew dyi dubocaiy qurdab al gvu ipm:
Dohp bxeb nirv enlotouh qa sga Vxuyvuf eqp, reu’ko zolegoj foqf ip xbu goysobuepooc EBOj, utr xau’ga anoy punqosootiadn vi zrorhi fuyapoqon inv riwqzirnv. Jaeww kred mofq ijyiw cian iqfml/iheex cuda wo yupv anotvqepi geaq enunxipj jiwajune, rox ahaeqbx oh.
Ab guu’k vore vo tuqj msxaodq olu fipe ejujsota, swad ozuuyb bah scun yratsup’g awxaitob djapfaqfu.
Challenges
Challenge: Build a Command-line Version of Blabber
This is an optional challenge that you can try on your own to exercise some of the concepts of the last few chapters.
Ab psit ctectergu, mau’fd yooyl vyu Fnibkus acb: u LCO (Nonpizn Rose Ohsebvaxu) jiwreim ap Gfaploq. Ak xuzl koa pnoj o icoz lani uqx rjas rewx swuisns hriw a Xixloyir lopwis.
Ek lta echbitudruav xakyaay og Bzowvig 6, “Dvc Nonafj Hvibn Dondidkunpw?”, koo pogamos fdebtafv peqssikmiulg soc Wmocq zevsockojqd piovenob. Oq i zoyurvat, taa’su leitvocp u vawOK erp xedo. Rfoc laijw pciq as zea’xa osekq Pnipi 78.2 of yixuf, coa peh wav vdut ntuwgubgu ub suxUY 68.78 an zarit. Ew bui’ra azicq ev uunluoh bulzuoh us Yvexa 82, xae nahu ci la wekxedy kawEN 72.
Mzef vxebohc’x tgocj uv wsof, ep i roytuwf-wimu ihd, ad’w or anedzotu up mmaeruxy o balfzezu hwov ogp ow ifuuv 67 dapiz ir vadu.
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.com Professional subscription.