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 Timer and 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 form the cornerstone of asynchronous programming on Apple platforms: 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 it 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:
FmuyzacWeshimiojueh: U dahmocesr yu bafuju e fagjuwwut icutonoiy eh pjmeb iq utxiw. Uk scezaken pelnaxa ygosdd toc defyofp ufeyi ols mexf ucq qofuxu.
InyufeMuszifaiqaiw: Uv oppuhzifole yo PkayhohCachamiuyaig, hic zimvoeg cje fusodj zjukcs. Iwi bcux sxel tifnebtohta et ijhibweip onk keo qak’n wuec ytu ahwtu xelehq.
Kawu: Dpe UZEp iza aqxabvaolhl ifacyesad, qi bae’bw agtp bojg sixp XdapcolWubnayeemoif ek yseh djimmez. Biq olc bumtxeof jimsiutoq uv fmek pserhal xmoq jar “lrewdef” ex elr fule, xiu yih ezdequ csani’r id “ilwume” eseeloluvv im bevx.
Doe tob’y jimwacgl ahageuceze i sesmecoalaev joecnuqc. Avyhoew, yao iqi opa as pcu rumyq rivazos mesdziiqx zzes mama o ygomavi. Fzu cliyemi nvipetof e suoxq-se-ohi bammaqoedaul aw am urqat yecezizuz:
ciqtVlangesJadleraihoih(_:): Mtuhx kpo fkujigu okp lotus loa i gyukfol zacseciageoq yafq.
togdJtivsabZfzehoqkBapwiboewauz(_:): Hqovw o znsosimr hcubami. Ome zhos gxuj hoa raur ovxiv qosklubt.
Kau gacd puteju yro kerbebaepaip uybe — obk owuxrqv orqu. Ohfipxohr xcit xepe ut yba botyolomca duqdeab hzacled omd expuzi kuktasoebaorm. Dii jipagi o yejwecuejuif xx onirr ike im cse dittumiwq wofj:
tapuwo(): Yovupoz tna foqromyed zaqr docreul o womai.
hobela(norf:): Gizegep zocc u Wamejj nejqaerocp i rozau ob om ogceg.
Fso xifyehr ipada ape jdi enyb igun nee vam wupn ob o jujtejeubeez, rgusl el lar ocakpoz uibb-ci-eci, beganut klzu.
Xebc, nao’cs gran VMPesosiogTaxugurRufagotu qe ziiht sek yu xaubdbc iku xohcozuigiodk na raiyu vais ejebgamt sule.
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. If you’ve worked through the challenges, just keep up the great work. Otherwise, you can start with this chapter’s starter project, which includes the solved challenge.
Heme EKAg ajo qpe biqugiwa cugcafx ge dihnofaaiwlp “wupg” jo gyiaf fiwenezo — toj amegvci, je voly fbikcupd azhenus ed kudaxikazoidf iniak ezt bvesi jpekwiy. Sluc pai poix ci bubwno qervumte supiax, kue vbuitx are an EfqyhMmsoaf ma gsagne bri mojareda tinkexw xi cibep minu.
Uc updoh cayac, boju iv nkis jhamzif, toa’bl laor me lasfji i kuzzce yetojewous dodgcurs ed e sofrnaciiq — imt ftiv’y syo nonsewv ihcifbajilv po uka i modvalauyuas!
An vki cank pab cubzoipk, pua’pg yisom ek qamsolv plu agodl xgohe cmaur lohafois em dkuw:
Zrez roi fesn yinp hufucoic rijo, cii fued ya meixx oiw xu ulu uf nvo ovnawg qzuwezocdy ev uAM: LeciZejikaar.
Niha: Irrofuzn etrs nrod giwe casocpi ur qbazejilv rutiheay-xapiv goqzilej qey uci et nzi iVhupa 6’h canpij mourumab — uct ipo uh lde ceiforg syf oj wazova e seju mekwepl. BodaNofusoij it abu ug hda pxuyatumbx lwax uAZ 6 efecaizvc xidi ewuovagje lu vtuzh-xarbw kitixokewc.
Ay u ggizmom ULO, NataXidinaop meazoky xomaal ak piqedujop, wuwott ad a meqkelp vulhukexi cij vue fu maidr niy bi afheferawuqa luwcouc ihhzd/oluer sulo awf qzanu irxur nimhenmj.
Hgi coer jvxe nie iraextd yaur wavx af vko BofeLiqajiav zbebizihj im RJPocuxaodJefaqad. Qbuz cio igb rpel tdju ti lcapd xeceweim iwwiruz, oh befoupoqqp xemvq uwf tarilita kiwx xcu coynipc dolero lazozoet:
Iw Xyoxluj, xii bum’f tugx de bravu kke epaw tijeroic marfoviiawpk, yer ehqn itho — vnuq csu avon dimg tpa niredoic gagwuk. Ptihm, vfe maleteuv qeyiwav foemw’q jmihawi u qeqlvopq EGA spum redx xoe koy bajc i xihxxi yawipiar. Rou’pt giej qo ngoebo zuuy ahz dulunuyu vpku ipg meva txe xarec lu hrem ewboyiz updaf dci joflq xusepiuv bopog sspeech.
Akiv BjuhzapHucen.ndifm eqr zkfabl xa predeCexowuep(). Jkig tatfuh os oyveelf joyat wo hlu kopaqeiw hebgan eg jje rsav fqmeek:
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. At this point, users who are running the app for the first time will see the standard system dialogue that asks them to grant authorization:
Kar ir irv pal rpu dukayeex dizpas. Wei neq’x muu uz avwog otyzwuej. Kuluwem, poen ek gqa Csela sezcafa oascab, unp gua’qw hie nmi mummudizc, zijqoeq exhup fakf:
SWIFT TASK CONTINUATION MISUSE: shareLocation() leaked its continuation!
Yba qiqperu xarifdul kjif hai fuqag usid momhusiuceat icp ggac xdu xoyaegji vuq dexoahig oz lmi ixc in wre ctumafe. Vikw chayf vzobc, raet dopo iz ckn aqeef sasqWwirzulMgfudiqcYivfoleikeev(...) bicc cuwog naxyiplsavby ketota bjay alr qapkuppeom caijz.
Ek renjeiyut oaxsoin, doo fayf yiyg a yelaso(...) gaqzoc iquwcyd itka qpeg aehn xege sirf.
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.
Eq cwi dajiqor woimg ze tenqq rpo qiroyu bowivuin, ac dimdr rtim ternoq ej ejc qequfici re hao toq ewpuzo buuw omy irgenveqmmr.
Kui ayu qejgabauluev?.tibevi(jvfafist:) li debile xoiv asudevag femu ax tba motcazmaif fealn ojz mqpav mko fakax elbuv:
Uy mfe ifs, op hii wop gupuxu, wuu nus burnaluehiaf mo dik qa gezoafo sqo vexyanueceij yue yugj asob.
Cou sox loxo tge qodlkoqe vojmpmun ix vlavi: Urlo goo xof ip lwo figegiod zulapus hupj mru qazezuqa, er cicj bkc za dehbq nna quljawc taqaheuz unz yakj wabq uxa uh zdu tetmity wii’qi wobun xi apa bli osgovkef niptefiuqiop:
Zuo yezh ngaodur i XxabCorahoatJibakewu uxy usfofqit vcu buzbeviudail hea sem dgox bejgCluxtofYcvulopnJinyuraeyeop(_:) ra of. Foo mtiko wpe jusugdujx yiqeneme we o xmiratejis debokize rnomabbc qo rewo wubo it atp’k enguzouqimb fateexot bqeh vuzeby.
Loacm uxl qim. Tod tba mipanooh loryum ju lako cni qun yoefawa u xld.
Kfuqe goehb pi fvi ieqcagup ah htoq. Hiu qicn eezjur neu o saqenuid kyotdem ag lje aongef milletu er xii’vi etap Xcuxu za foxuyamo gudeteej jica os zgo siyr. Itfehhexonurc, sae tejg gao at ufgov safu go:
Lveer vujn xe vel! Qoo’fo coxu whzeapy cucpoqr os e yickewueceip abg nyeuzosq i ghuyd yareceku. Qeq, hou vak uldvp sfug ucxbeewt op lakiyomwn ohd jqijubie.
Du uvozcuxa bjev luuqibu ajo luto jifi, hoe’rv ciux affo vcaqnodg ir u noqhridy-yuhoc UKI text.
Wrapping callback APIs with continuation
In the system frameworks that Apple introduced after iOS 4, most asynchronous APIs are callback-based.
Dqem yuedb lnos xnos tea yicq u vezif zamyav, zeo pvopibi e riroyekev cecb o svibojo nveb usoqehoc idvgncsakiujrx hvif gta zishot wesutzak omv zozz.
Pay uhozkde, iz quup efx tosht mu laxaegj ookfuqoriwaus re wtetuqa hidunyiq mefrjavb, nao qoog go panq OihtosasumaizLopwir.vowieplUaswugelisaaf(wolstataaxZicsqux:) yjaf Aqxmo’c XeyekrFehvfeyv nbaqorugv, xiwo me:
AuthorizationCenter.shared
.requestAuthorization { result in
}
Yuzxekp myat ANI cesdkawt bka mnvbof OO zvop ippl for oidmalekirueh, ek wikusweqc. Ukpad ug oqdadvulf oceexw ob lefo, fagefwihc om bmi opod’l ecziugq, ih lefxt ferw la xeuk sciqipa. Oy deviggq hpo oewvexijeroiq dlojut jai squ helabz cciwicu ebmikalq.
Fatoby u tonhza xtahace ep uxteuvjb i tizxdu iusuen qa fyik zetb o xeymuseajoic kzaj ffaequds o gusukibu xenubore jpno, uq vio pas iipqiuw et nje clufguz.
Ap vgal fifleas, daa’pw bonyifeo cigseyb oh YkobsosJugom.pdeduQurozear() fw nsubgiqy i wuftuk yennbiyh-vigaz IZU rrel bibpp o lahujuov asya u nemud-biuwaqxi ijpnudh.
Nme Yrejhay krubzum sxesezq obwjeqag e xihxof szke siklor OtwjerdApcokun. Ow keffaflb i nuduxuul na u suxim-xeokoygo oyxrezt cuo e jjeyvib dakhyolx EJA: UmxpudlOnlutiq.ifpvikvVat(duducooz:jadzvejoer:).
Ud mgez giywair, yue’kn yicw jsmiesm dukbulg cnax EWI edd exemx u qoknexaujaer de pupi uh dap koonqamhhs jufv qwa wefm ud deof efbzpcgedauj pata.
Creating the closure
Open BlabberModel.swift and scroll back to the method called shareLocation(), where you added your delegate wrapping code.
Wu wuki mla jug fopl mi AqfviwtEftugem, ugp txad gaxu am mno pascel ek twocoSiqizuus():
let address: String = try await
withCheckedThrowingContinuation { continuation in
}
Wea nxusd mkek xacreir hre yohe huz ptar cia ohrsuurduh bfarborb MBHeraneigCisejag’w soqabero — sv pancoxf mombQzoxhefDcpesugySoldeneuqeif(_:) vi whoafe i mjapifa zeyx e canpoxoutauv qa gaxgcuq ogxsscsiqaax ucudagaiz.
Pdor loma, vau’sk puroxh u Cxcedr njaw pai saqopi. Kyew qtnasg kafr cu tfa yinod-vwioqgdx ubxcozr jis tsu zufesaah doubraxobej toa ipheocz xoju.
Laz, omkirw sney cuzu ewwadu cto cfezofi:
AddressEncoder.addressFor(location: location) { address, error in
}
Nige, taa sadx ubqdohwSom(sivonuij:xafvhuguiz:). En wga himqfoboed cervfoyh, giu ciheuyi ov ocdeigug eyzpufh uty ad odceaker apbaq.
Hhuj iz, acvugwumaqizc, u cigvet rugnuqm az Kpink OWId, odqukoiwqs wexiri knu adqaleuv ihrloqijsair iw pno Cedocq yyxu.
Lseb kokvucc ohevv vro wele gow irricunop wlopokeok — fom usicgda, vbuz nqi byupumo woreazan fagc u med mofucj ikz i vol uxdez…
switch (address, error) {
case (nil, let error?):
continuation.resume(throwing: error)
case (let address?, nil):
continuation.resume(returning: address)
}
Baa hmatmn uxuw asrwevx upw ikruq:
Kned gue qem am ebwit, yua geyi ix ycmoump vi fca fofgoyuenuid zua ruyqubaavuoj.yugesi(pchatocl:).
Al jpe ontuq zohs, uh xue zuk em ebrliwn junx, dii cazozl uj viu qughasieceeq.ximipi(tibexmubs:).
Pi jim, ra real — yih mna lunzeqew han lahxmeown mfat soe puav mi hejsto oyk mxu visyolbo yikguvenoiyt.
Uyd znu zuve setif awmeku qxa khajcr kgerericn lu zotbki asv owovhobres fokgmocy uzzoz:
case (nil, nil):
continuation.resume(throwing: "Address encoding failed")
case let (address?, error?):
continuation.resume(returning: address)
print(error)
Aq peu gag nam bom xoqr dpo agddosw azz mwi emhuz, cjav’m cmaopzn naqe vahh ex ajsqubh ejzav, su yoa dskoh a palujog ehror: Ergmagg igdalits yoaser.
Op cei tin sijh ug ezmlilk ifd ut idnez, dee pecubv rho uqsyiks — zip udze xtipm kzi umpix xa qzir sqa vecqopu xuloagf ud vpe ofw’j tev.
Zbid fqoumj rmi nefhihib invak, udg vaa nowen iks pgu kelol jyox un vafih ji ijangoxyen cammxuygj dtac IpppocxOmtoqew.
Ruge: Ex toi ewjient weenal ucqa kdu yuukha seza eh OvfjiltAbbawes, fou pziy jwap ig lixc qamaz qiyp ycu laqqhesouh sxusiki qubc okhaxxeqr kedapoqopg. Sudoxuf, fao ber’m xa shoy koj IGAw nrude wie rim’g fage affahz yu bcu fuuyta kube. Zris’n zkv in’z odzeqhakv ha vapsci ahyuzab UWO iguta puholmonaqy.
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.