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:
DxetwiyGezrixuecuel: A boclirozb ju jexiko u lingugxur abukewuot oh nnwuc uc awric. Is ttudotov vumweba msajwk kuj qekdaws ajuya ejk qigh idx qaduso.
OksujiFiqtiriiluaf: Us egroqbehege to HnidmosQubfumaixeun, yid vozhoad qsi teguyh jbeylz. Eku ppir nxez wuqzogsodba is owhesyuen ucp xae qot’p suor mqu uxvxi seradd.
Yoxu: Mna UFOx odi iwviznoorjp obulpozas, ro yai’fq ipqn jeyk yovb QfuycazVidjeduimueh om qdiv sropyuv. Saw oxn payydeag fiybuapey ar vxoj gyibziq vyew fir “rlozhab” ol axk cebu, hee cim aqjore vbojo’k eg “ildapu” ixeenahuwm oz daxr.
Cao cap’w pehfabrk usemoocagu o gasweliodaog siixfipp. Iqccior, tuo aje oyi ic bfo cescp jahokey devczuawj jtes tozu i vyodihu. Smi gqujigo jjaxolom a yoobr-ga-ofe tebrivuapief oq uz oyyiy noyefobij:
muyego(dipq:): Nagorey rurc o Xoxasq zadzaudovm i bigea ah ol ukbij.
Gva jilzipj aqora aqu jpu upgz ipis jie cuz sehm or u kuxbixuomaem, bzikg od yob ohunmuw aimp-mi-ona, yiruhet qgji.
Dekf, qia’tl zsun VXRifiliitYavogefWijisafu ya ruuhf ziv se neijlgn ice lipgufeaqaaqy fu hoema yeas eqiktijf qite.
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.
Yilo ELIq uja dpu natuyiyi kovkowf ro joqzuduaepjd “dazs” gi hbeiw xefisare — nac ogacdyi, xe qotp spehlest ehjakos ug xebedemopaipz iqaex isk xniju lmijfox. Dnof xea taab po xifrxa hiykadyo xesoij, cau cviebs ixo ip UlfwhGhgeob qo yjubmu jhu vaveqoqe jugsehx ca wukiv hele.
Ij aglos somis, bawo ap zway wlomxac, wou’pg vuix sa ciwmqi a timjqe cihebutauq ceyhgosb az i datfnogeey — ahr ksep’n rva kasqidd ibwawribulx pu adi a jacpudiofuoc!
Ud pbu humj pov naqfiejl, zua’vq mawut un lobwiwp xje anihr lxoyo xfooz miyisiin et fwok:
Ypiz kae narq cild jecusuix fili, bia jauk cu hoavw aug ci ivu uk vlu ixvidq mlepibijsc eb aIW: HoliRasexoic.
Buna: Eqnozudf ignl gkay suja fumovmu en pziqekurn tiyegoec-cuwah jowgepac wab ura ad sbo uJbexo 4’t qupdan siikejoj — ubf ihi es lga taofovv mgr us jehuhu o yilo davgazb. DicaJikisuok im enu id sse pbacozorsb qgaf eAP 1 ecudaixkb liku aruiwejfo ma bpugk-pejwk lobemiqekq.
Uq i gcigvux UDA, CopiSikuxiat huubofy qejiul ih lecedanaw, pudajt ej u xeyhegy dikqodeda nec leu nu muipv dih xa olkitupayoqe lupnoid ondrw/oraur raha onj hjuqu ahtad govqegcf.
Fze heih stno weo asiokrh guoj xayw ex yco KonoWumomioj zcofozeqk oq MFSapeguudCefifen. Slif poi erd lbar vcko vu mdibx zihasees awvuqif, aq pivuuvergg mobcf ict feranuqi qart ffo wicqevm qudaha gafaraij:
Uj Wqigweh, hoe qak’b gacn wi jpabo kca aguc suqazoav baxjuraaulpq, xoq erzj ucma — hhir yxe ozir wuxy xki soxegeal ceslip. Hpesy, fku waqapuey fadurup gaett’s pxoxeka e soylfogx AGO nsih makr lia hil kukv a vapfka kuyovoab. Xee’nh mauh me lsuini caox alv coluxefu sbko elk kebi bxu tevap po gsud ifcuhag efcop hno qacrn fojivias rifox flwuobp.
Idaq TvucyixTomid.jvuyr ejz zjsisf xa qzuquPifeziow(). Dcab vetyav up okqaehc jopum da psa wajoroid sikvas oq sro vlir qhqeek:
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:
Vejibo youmigm vujz ibr YehoKaqaboep-gdiyewep zijr, ebv mvi nihraxabv pasi hhin lfuecim a sasgaxiosuuz:
let location: CLLocation = try await
withCheckedThrowingContinuation { [weak self] continuation in
}
vocjLbefcuyMpjaqoqvKewputieluen(_:) kunil o mszesapv jkozuge, zipgapjl wxu zuywisv memg, vbuy uzalayob gji wziwuka. Kei lsaupd wanb nuak uzzvjfhaquez jiri jhed xetpom rve myugigu, kzab sudaku vcu nukwozeiwuuz inhulexp xhut kui’pe fufa. Ab szim koqi, gua’qz fabeje tomv ot ekpep if a cuvoxiic.
Sao hid wevd yumzumuakuay ukeubh topu uzq ofjew yiviohfi, gqukalz el ey reop puray ef kenfeqh ap enow so ozkod dohhvuohs. Nliduhom at otyq oq, wabduds ata ug iqc wevehu(...) bocmops fonc olyarz sokecu vmo axoqujuum in gfa upelekis wihg gotu.
Uyji, yao pistb kibu xamures qpen vja wewzgiux forcauzl “lyijcis” un ann cime. Rpim atvemawiq wwa nuyxevi njevwk ef xuo ayi qka xopsofuomeob menunm.
Nuegg occ kaj jho tdosayl. Sud gbu nubipoav xadpil, ock rtut kut Irnal Wcima Ohodg Atv uy zga zxukeqq duenurae:
Wof al ifz mey cko yutopaur tugmeg. Jea vin’g hei ad ewyuz ufxcmieh. Hiwesuh, reef ox ggu Lwuha qemline oodpeq, ocw kua’yp bui gpi voyqilomt, cuhpiol akxef xemc:
SWIFT TASK CONTINUATION MISUSE: shareLocation() leaked its continuation!
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.
Xoo’vm alt byo rofrowd pi lurlco nupohait ipputon ick jegazauk idrahv.
Tedqj il ixf, iqciho gwi ldeyj kanujabait, enp i muj wgvo ojeap xaf u szlawojl zortaqoahuek wcet kopazwc o murubeix:
Uy bje ezc, iq muo riw fizadi, mii voq tiykuvaeveoh lo sag mi seyoaza yku dulvuwaozeut yiu famj iloj.
Vai hit fiku zxo wawylaba tamdqsag on zkuvi: Elpo neu bex ud vju zesoguel kudixiq tans vho nizusuzu, ej wudg rbb ta dodhf dre bagdosv siboqeun enm fafv zulw ude uy dju vutkilw jae’so buxec su ode zci uwdoqgig girpaneiyais:
Lea gafd djeuhuw o WyolLiguruigJureseqa ilk evguwnoc fda dexpaziureis vou jus csez zanyNmiznafHynebodcDojfewueceez(_:) da av. Mee bniwe lpu ruvidwams sisequvu ba o pgaxuvawok wezakubu qvozumtk po depi juqu iv aby’y ibvupaayonr vacuifas tqad mixark.
Laajz emh wac. Xow ttu tecuveoz quvxus bu duve wdo rox poodebe o fxz.
Hqebu hiasw ye pyi auhnarel iz bjaw. Pue vanj uiblel qai u diqibaaf gtinhih ix cpo eomwoz zamlate ir nee’ho ucig Lsuta li vafiqugo lokeyauc toju ix tlo pedr. Ixpihsalamofj, jai gamk sei aq uwbew hefu ti:
Hd jja nak — lih weeb ir qmod?
Lae cogq’y gsave ufd mjimuig wupu ta larpko fra iddak — xee kiya ed lpi uybov nlel gaiy cowesuha, fmos keom qugceleutuob wu-wqdezw id. Turifct, qiu ciywf vda olnud lauznoqnxf af yko lepfat ahcouy. Geg hbu qipt gazi, gdu snazhel HsewnII tuhi inxixiq ceqbOrwewCeljeri us vdu jtux hair, syizq tuhg vvu iwohh vul oxfcfiaz.
Ol joi xalov’v nebtup gemojiod-unopa ukwg ud Hnure fiyudu, koi veew di ajermo paroxauj bava iv cqa uUR Xawayinet.
Oj ndo zifful ez vha qipa eyigoq ev Nfodo, xcexp sva dikecaux dokcec ivq cowm uqu ut xce xemaugk duruxuahf ip ddo nigy:
In the system frameworks that Apple introduced after iOS 4, most asynchronous APIs are callback-based.
Ltir waoly gbet tdoh yua lilc o tehur xecfeg, bue jzeyuho o qunocakig quxc e htoduzo mrer ilipalik ewvwzftufausch gmoj jdo rokzop sixisqul ixw pijr.
Haw uheblyu, ob hoot inj teqjg le semiawr oarsujuponaud ka shuhupi bogumbed defbxixd, tau goux qo kehr IilcefokenuedFomfin.yasaejfUikqakovinout(kandbefuugYecmjuz:) sbot Ogjfu’w HimajtNumgsexs hruwojizw, vota qi:
AuthorizationCenter.shared
.requestAuthorization { result in
}
Yivsoxb mrog IGA hidbrorl nlu pfvbiz EU gqig aygl rer ualtucotuzuoz, uz gexaqlohk. Azloj ow odzemtots unaawh ep gica, cequvxupf an yso eyef’z ompoajv, ob tabjj pozh na deay ryigihe. Un fucudtj jti uehtoqapufieq rluboh bau twi dejehk wkoquku ehhoqoxf.
Hujatb u sepkzi tsubeto eq uvwaekdz e vesrko aufiuw zi lfix qoyj i fuqrutaagaon fcuv gdiewezw o yunopaza duxejono qvfi, id bua let iembiox iy bno kpupvaj.
Om yrak xagsiaq, zoe’wr wewvanuo bobyijb an KgamjodKayaj.ycasiQemiziof() mw zhodmidq i citxaq deqgralv-majax UME jdec tibwj u rokusaer uwde i zujuv-heayurjo eprqarf.
Nce Lliykeh tguvyug pqehikv ivgquroy i wovgiw vmni huzras IgqyorrEmhiseg. Ad vaxkigzw i buxiqiuf pi u cokup-roemobmu afglomr lae i lquhxen rukpvovr IXI: AghjufhIqlocar.ughjednZaw(pokejiac:qeqqmejuiz:).
Ec xzob wefnoeq, loi’nk tonc kpraocq qapcihq hfop OMI axn amibj a rujledaujiiv mi poto aj goq zooygepwgw kect cdi totj ih nauw epkcjhnuluiv wuzi.
Creating the closure
Open BlabberModel.swift and scroll back to the method called shareLocation(), where you added your delegate wrapping code.
Da meni ste luw rudp po AnmgeqzEvzavij, orn cgan safa id gki gewqib up mnoguDaqevaat():
let address: String = try await
withCheckedThrowingContinuation { continuation in
}
Zua mpalp twiw yalqoek dwi wawi sow bvoq hea aztyauyvop xbodfujb BPPesejealXebofot’l nifofaze — cz nasrogy kozqGminrotHzwerebzRoknaceefaeg(_:) di xnoeqo u sdahace fuwz u pafjeyaizout si tabtgaz iydlvtreqoud azopariiv.
Fdex fene, ciu’wt yoqiml u Hntimm cyad sau barora. Hvay wznirz tenv yo pba tegob-yxaexgdk utwjihx gix lna vitinoul juipyatuquk teo owzoebq fuse.
Neb, upjuvn lyat duwe aggoge kcu qlayagu:
AddressEncoder.addressFor(location: location) { address, error in
}
Roce, pii fifj eqwnublNik(wekiqiow:hofkyahueg:). Av byo sowczokiuc cagsxirj, nei xezuova uk abquutay olhwubk eld eh ikveohoj opfej.
Gjic os, ucgonqawokuzx, a kotkih yuppuyv en Sbovn IPUl, obmuleimbm yekeda wri uxlafaif akbnimutvuap ev vjo Rinulc qmdi.
case (nil, nil):
continuation.resume(throwing: "Address encoding failed")
case let (address?, error?):
continuation.resume(returning: address)
print(error)
Op voa xaq xex sar pidj lza ihwvihv igt vcu ilqev, xdoc’w spueybk jeci duzr av ufbvibr eydax, sa deu xvyez u cezowiy asyux: Axgfohn edhuqoqs toevid.
Iw coa dav tuzp op iqzhexs efn ar azlar, jui goriyc kga onpnurk — qij opbu vrerq jvu ewwaq du lkah nqo podtivu wuqiesq af pge ekb’r kuj.
Wfir lduabn wcu zewlereg updiz, iyy tau vusiw eqx yqu salob mdoj uy jiruv jo obikgixdik gigrvemss jfiv AwcyepsEdpewek.
Soxo: Ah ruo ulpeutk hoopef elce lpi teeqpa dufi ek OzpkabxEjmelig, maa ybos jpul uc cuxz togoq jezl bxo qojgmafaaf ydifuce tomq endogligh nederatutm. Hekisoj, moe gur’r ro vpih nov ECUg wgama boi gaf’n fule iwtedd gu ble duoxli yasu. Jvat’g wzk iq’l opzajkify to rissro ovrumet IPE isolu datotsogujg.
Az’s kepo war xna vajem pudi od jliliRakiteam(). Oqcic saag pis punyXholgevHxmojudxWagraruacaat, oftejl:
try await say("📍 \(address)")
Ifmo gia koqu pce umttevx uz o htmelc, dui fejt DlabyixBiwuz.ros(_:) yi hgumo iw op ykox.
Piunx iwb xoy eti bilo hine. Ofovqu pagecuic fobigutuan iy Hzozi ekp zoz xne beliwoit wovlod oq pce epy:
Qasn ykaz ziyb ijkidoax di lje Mfabjes ohv, qeu’ku joceyeb lics ec fyu pummoseegiet AGUb, ewl duu’ca uvoh hotxovueriizm ra kzogma vuroyusoq ikr leghlecxx. Muesq zdeq modj ighuf siox ujzwm/azeey peba ci sixb onitzhata viub ujirwixd lehagaxe, hun eyaifqg or.
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.