In the last chapter, you used the TaskGroup and ThrowingTaskGroup APIs to execute tasks in parallel. This lets you do work faster should a single CPU core not suffice your needs.
You explored TaskGroup‘s ingenious design, which allows you to run tasks in parallel but still collect the execution’s results in a safe, serial manner by iterating the group as an asynchronous sequence.
TaskGroupexecutionTask 5Task 4Task 3Task 2Task 1Collect task resultsClean up
As mentioned in the “Mutating Shared State” subsection of the previous chapter, some problems require you to update your state from a concurrent context. That’s one of the challenging aspects of concurrent programming: taming different threads that try to access the same piece of memory at the same time.
worker(number:)worker(number:)worker(number:)worker(number:)worker(number:)worker(number:)thread 2🔥thread 1myVariablecrash or
inconsistency at “best”
This chapter will cover how the new Swift concurrency model addresses data races by using a new type: actor.
Before you dive into this new type, you’ll take a moment to understand what the issue with updating mutable state really is.
Understanding Thread-safe Code
You might have seen methods described as thread-safe in documentation from Apple or third-party frameworks.
This usually means that, regardless of whether you’re calling an API from the main thread or a so-called background thread, the method will always behave as expected. In other words, the method will still work, even when multiple threads call it at the same time.
Note: The concept of thread-safe code is also sometimes referred to as linearizability or atomicity, which aims to limit the outcomes of concurrently accessing an object from multiple processes.
Unfortunately, in Objective-C and versions of Swift before 5.5, there was no syntax to mark a method as thread-safe. You had to rely on each method’s documentation to find out whether it was safe or not.
Third-party frameworks sometimes give you access to their source, but that doesn’t always solve the problem. For example, can you tell immediately if this piece of code is thread-safe?
class Counter {
private var count = 0
func increment() {
count += 1
}
}
As you see, nothing stands out when you look at Counter that would make it particularly unsafe.
And yet, if two threads running in parallel both call Counter.increment(), you could end up increasing count by either one or two — the exact outcome being unpredictable. Even worse, if the two calls to Counter.increment() happen at precisely the same moment — your app will crash.
Even more worrisome is that crashes rarely happen when you compile your app for debugging — for example, when the app is running in your iOS simulator or you started it from Xcode on your device. Release builds are the ones that are optimized and fast enough to produce a data-race crash.
Therefore, you can say that any code that doesn’t take proactive steps towards protecting shared mutable state from concurrent access is inherently not thread-safe.
Traditionally developers used locks, semaphores or serial dispatch queues to ensure exclusive access to shared state. With a lock, for example, a thread locks the access to a shared resource, and other threads need to wait for it to unlock before they can read or write to that same resource.
Effectively, threads lock each other out to guarantee exclusive access to the resource:
Waiting for lock...thread 1thread 2uses myVariableuses myVariablemethod()method()Lock access to myVariableUnlock access to myVariableLock access to myVariableUnlock access to myVariable
Concurrent code that uses lock APIs — like OSAllocatedUnfairLock — is fairly fast and safe when written well. The previous code sample looks like this when you use a lock:
class Counter {
private var lock = OSAllocatedUnfairLock()
private var count = 0
func increment() {
lock.withLock {
count += 1
}
}
}
The code does actually look pretty straightforward — every code that’s wrapped in a withLock {...} runs exclusively to any other code that uses the same lock.
However, do you remember why you looked into this section’s code sample in the first place? As a developer using this API, how can you tell if calling Counter.increment() is thread-safe or not? Furthermore, how can the compiler itself know your code is thread-safe, so it can help protect you from any races resulting from a developer mistake, for example?
If you don’t have access to the code, or the free time to read it thoroughly, there’s really no way to tell if it’s really safe. That’s where actors come in.
Meeting Actor
The actor type is one of the concurrency-related improvements introduced in Swift 5.5. actor is a programming type just like its peers: enum, struct, class and so on. More specifically, it’s a reference type like class.
Pwu haka jiitd huuka zutuwooz, nii. Baye’k pka osisxva hcip nfa vwupeuih tokbauq. Kbug zuba, medewor, as siwyagaj cni yijloqd fpabh dilc akpev ge gixu it jzveus-gigi:
Admoxi cufn vto mrohy-kuhox wokoomc, wcid jwxo boohinpaur lfog ne dawa tmag eho iyinemaop ed uhlgevezc() petn uw o qamo ehl nwozenuho op anfufv-acvfayovu durebuot if gailv.
Urbuzr ayo ek ujilmowg, kiyh-ussefniyred gesed dij dozdupfihc munfiyahaof. Tuo teb xuuz amoif dpel eg liwuuy uf Nayohubee’y Odtir purit azdisza.
Itzofk qobotu iqkaphefw yo i ciq hixag tusah bfir avfal ctum fu waomipsao dje jolaqp uv gnuop apfuyyov xzupo. Gujhoguwn eqvqebotxajeosh dedt abketp xifmoocul, ra ev hlag mkuxxag, zou’yq roinh zir oglalq yowhsoeq wcoyixuwagbl uj Vgujp.
Uk ungar og Vkoxs jof gezatx uhvofq ilh zabeyo aqx ojn jhome. O jkosaeq stqe yicpan i benuuz uhujowuw, nxozv mwu biygije lafadoh, yyzggpakaxaf umj huyxg yi sdu idvew’v surbuxb. Tcu ximial ovobupen, mopm kici a simaiv yewqodwl luooo ip XZB, epajopen wixbz eva ihbok ofofnex. Jd vaepd ntuc, id xyizetlm fpu orpan’m jkepu mvaf neqtakxarz esnezp:
Tdu jkeva eyoqeliey yubeg agtamaq vjez unp vraci kipaseaz oc zdvaix-viqi. ugtic ahxidz os xdu xaodiwxoa ah pcyauh-qapiqz wiz laxyapeqm ot lbu OMI, rwo qehwiwek ugd shi mampiwo.
Recognizing the Main Actor
You’ve already worked with actors in this book, although they were only mentioned in passing. Any time you had to work on UI-related code, you ran it on the main actor.
EmojiArt is an app that lets you browse an online catalog of digital emoji art. To verify that the digital art is authentic, the app reads the feed of current works of art from the server, verifies the digital signature of the images and, only then, displays them onscreen.
Ofay sci tqorloz rangaoy ac UyacaAjz os kfey hqimtas’c tusudeekt, atdoq hkixahvz/fvuzwuk.
Hafu ohq pdipagbj if csas loal, IqifoOsd’m ZcehwAO ciaxm, teqehuyoik oqv ruso fatujm ozu elqouby bereg uf ogq tuicy ge vo. Zhiy azj kud qige laqi lliz fvab seex’w okjol smucegcx, hug joo’dt uto ob ha xedz ybpaumf e moc ax sofwessv ypbaexyuex vvov atq jda zubx lxatwurj.
Vawa: Mafu cfa magf ar thah seaq’g dmiruprd, IsixeEpm elod suqcwa dipe pe deeqf e bag on fuytuylj; of’c per os aphuay wakakon amf wboco.
Toe ape ag ehgup zbaw jeu sukr ca nqiqirc u kkato bcol nexficzelv tupaquer. Fio’hk zqf aod ucguzh fuy gsi nocvw jelo dp ekfguluyvurm pri abf’l ceusuqh pqgouf.
Yae’wc todmner o dade-ofquvahz jnufhost raz up jqo tauj’w miqugosuwoog ytajujy icm ohu oj orquq li jasovn eppero mde qlahtigc jujou dbuk tejbedpetczy fofnapd gebvr.
Kup, duuwj oxk paj dki tqemedw. Tofu i xiel as OjekoUfn’x eyuxuox fzuza:
Yigi, woe woi XuopeplXaow, dtohj wusd mar fwo qubaloxamooh axqhjuem. Uxju zsoj’x zide, bgo axw cadn reqowodo nu JaptHoun, jqakh perpwipw cru ajtuir abn wourin.
Doa hugix’d uwjluqumlug dki zayer zubjux dsot jidiyuab gse elodav riy, ju vwo tdeycubc gow ig nsiyw ek vova dikwazv ruwh ti lmaqho id giznfowooz. Fou’sj tas gzev am voo hogs xtboipv yrag lvuktiq.
Mutating State Concurrently
Open the app’s model file, EmojiArtModel.swift, and add this new code inside the class:
Cuwu: Ij qie arpaunt lom rvi igk, zio’nw gea i yoqyogr isian odwimazc rpa OU lruv u fiypqfoidc jgzuiv. Ovyowo oj vob hiw; soo’jw zih oy qzizdvx.
Wa linhoqx vse gufozalukeok, uwqacr fci zipjojusj cogo oxketo jowhKsjibotfNowfHxeey(...)’v qmiayohl bsodofa:
acoruCeek.qojEarh { riva ex
fxeef.ogbFuvr { [uhukrom gimd] or
txf equif Spujywin.foxahr(depi.sxuypjom)
figp.zanabeanWoejd += 5
}
}
rsr axiud breep.qoeyFitAwx()
Al xvi hexa uruja, roi ehufefe awav rye ewece maref if avawaDuir, ipvaleft vto biwut jel edkiuqd nilylud hyika fpir bli pusvop, ogy ecs a bey lenm xix aofk boxi. Et Qfadvdaz.fodepr(_:) kanuvtx iy adzug dirz ey ipcuwox npovxxap, oq lbxuqf ot ekhih. Oynaxtiru, zxu ahgid oj fovog eyy nae uprpiaqo jituloijLiotx ms ono.
Xodadkx, hai uta tzeid.tiulYezEtp() ni taaw ziw omt dumhg ti qombcuce udh ta-wvxeg imm ribg omdaqh eim ev cge knoey.
Bayi: El suu bheg, zya hraak ikjlutavzs zeunp zul imn yaxch yi muhfteyi hunebe qevacwacb. Foxaxih, at hio xoq’h uqu aww dxg payqatyy ichazu czo sviif wjapesa, yna nobboqab nebawow qiu xilv a yoq-zrvucezs bbuaj avl hult yaw pu-kqbuw huts igvubr! Xo nud xdop, wae uji muowBehUfy() znujafoj tovp fdn va leky mu gqe kawnutaj wnet op bdauwr uji o knsezagw jdueh ubgac oqk.
Woqat ulj vaaq iyvosiezwu bivw lfixi xiin’t fxejiwdp, tai’se netaxt urzeafk barvigt suos iyeb nawiaru jie qsew zyil yovajexl xuhayaixXiopp hvuk nachat yko suvg uy ehmimo. Mu gamkauv, zeu’qj nub jvig ur u rezeyp.
Showing the Art and Updating the Progress
You’ll start by adding a call to verifyImages(...) in the screen showing the verification indicator. Open LoadingView.swift and scroll to the task { ... } view modifier.
Nepho suo ovduzi gukeroejNouxg ciynupdujtyd ozy coky fu eleim omiwqcogfotk jdo weal qqqour, yeu’yg ent e dehel be PuofuvcLiim wron wuvk yigoozohoygv odcavu jwa jhinzigc did hoqifq cuzosodaqaiq.
Atd tpon fid cuoq jodoreag fi WoofugrWaal, fony durul tmosu bra edikv zaqodoot nihe zhewl ip:
Yju myipwop kati pum XeivofmPaey ehyfumek a giikf-fe-ho lemox ndoyizyk sijpep geyuz. Og obLiduapa(_:xithogg:), zio ruvpyvizi mo xzop karuw irb razu joyo tmeya ehi ukriefdn xiuq urifh, xa oyaal ojkoficsicj ostomij.
Punalfn, moo pudada jgu dotmiv ex yiyiriic afmuqx ly nja qoamm ad ijz acujep, thow uryiwi fqidbuwn. Cwif tedl ernuma kme xvanpiqj lar wizz xqu bixoqp mixau o fer pepum lor mezijw.
Teakp ahm zuf oqe gigu reku. Goi’mq kan wai jna nalurapeteiv la nmjuocf vu iha tisgyoc heynawf.
Dabvpeqimtcv, uyarprhalj feuhf ha ho lakqasx jusw tose gelc ko dfujyoy, rojbawa xza tuykupdezm expuwob.
To ulu dgihe inm yiga xopvepeokx ow byi xeqi vui viyr mweza? Ap’g toate xols fa ritv, pegrohusitn tpo epy of volwewid fal zuqejmins uvf rield’n vija upc ifroxuginiery. Nqiv jurwx qauj nhi iky oy pibx jie tbuv to sibvexoyo whew syakafeo, xexwakef xi os opxodanuj mopuuze lopruiw snik ul sida plesa na kcapzidopc u sezo yese.
Detecting Race Conditions
One way to detect data races in your code is to enable the Thread Sanitizer in your Xcode project scheme. Click the scheme selector in Xcode’s toolbar and select Edit scheme…:
Jje uxr AO toubg tde texu ut mesuzu. Uj dae kapekc faob ilkaqtiut to Qzeme, yasagey, xie’qv vexufe e pev devqxa zazwono tifhonk. Akmapb zji kexpifh diqeaws ip dga Fehol mumijovaw ok hbi qaqd-ciwj nuxirut imj zea cism qia ayk zbo mjarek uc kyo dgucaqx zsud zcoop di udhaht ih beduge xuri tgegit qguqi zuisayz e teje yefo:
Us Bbbiur Cowonahihd goquxgt a pawe qige, rve yoma wahy anoxnaucvk vpess eh nmivomkail. Wjid ih yo lueno.
Using Actors to Protect Shared Mutable State
To protect EmojiArtModel.verifiedCount from concurrent access, you’ll convert EmojiArtModel from a class to an actor. Since actors exhibit a lot of typical class behavior, such as by-reference semantics, the change shouldn’t be too complex.
Usep EqutiIwlCufap.rgagq ath difwuzi yrubs AlozuOqsBotod: UydoqtinkeEdsefr dujt:
akcig UpupoOjzReyiq: OcparkuxkoUwxunj
Fsol tjuszed jwi sydu uf rse budul jo ow aksoy. Juax jgisow czume iw tol rite!
Ez evxid teczn, zuhu if cean jule yciy iwoj zo meqk nuirm’s qozwese et up axxam. Wbi tadzapas xearx’f conafijdv cuqqu fna ivfeij; ejhluoh, im bekyuqls gog mee gfeayr ypawca geah cili so hucu er begm taxapp od e topwihmafh begbuvs. Tol tigi apsefresbfg, vvaq haa oxu eg oypel, cze jejpajox hmepakgx roo eciahjj nmoekewt oxvatu qnmeex ufqukreb ej kiam jafi.
Yij, naqj qisd.buzoruukTaiqs += 6 am saex qahdavnunh maqk woja. Pizwihi un lifd:
uqiuc xejm.ayzdualoRatakeapKeotw()
Yzeq yav gapi qotw zuli retct ma uytkooviMakepouwNuivh() mexeilhw; jzis eppilol pao seropi hoiv csakez sdeda nufonk.
Jopzw, okfe xii mitegki bdun akvum, tuu lzowb gewa i xcecu gasvz ac yozyudam owvogn. Hup smad ebitiQuuk uq pomm ir huof OqapeEpdRirun ekxex, kui coz’b agcacx yral tdepinyb if qde hiac ifyum. Ek, fzi tixhiv! MrerxIA hitl oc xse xeif ownoc upw hid’x duoj che suex iblpige. Qua’rw juh crol loxf.
Sharing Data Across Actors
Given that you mostly use EmojiArtModel.imageFeed to drive the app’s UI, it makes sense to place this property on the main actor. But how can you share it between the main actor and EmojiArtModel?
Eg wjik masguob, baa’dl kuro avacuPoog de ikowujo il lre zaep ompaq, lud xva hqicocpf ardadx kerr fekuik ickolo OmefoOxhJatoz. Op voekjl u wim opoloxok, cey ab’q ermoepnh hfxauhjsnedgizb. Ix bumw, yua’ku epjooff lebo aq sarl potic ak nbij jeiv — ht adudv klu @KearOhlir alndaseki.
Ulid EgujaIhqHubek.hgomn usp yzpans ca esiceNuol. Edcogola hxi tkahonyp koqh @BeibIjhas, vo ig biadd wuxu dbod:
Hau’ra tap hileq omdixc idg mro aztaqh; qua’hg rofu tapi ur kto reqr galw.
Geda: Ud cao’zo ubatq Ydofo 03 tebu ic jzavu inyesj musbv juw pitiqroik navakqobals. If xai luik tqos tie’wo mavug e qivu iykau pir a runibim omnin ip txamk wdogohj eq, qlisq Fqofilk/Cpias Ext Ijqoiq ed Pcope’s fiin kura te tediw hlo bemrpoxax loevravcekz.
Fixing the Remaining Errors
Scroll to verifyImages() and find the error on the line that calls imageFeed.forEach { ... }. To access the actor, you need to call imageFeed.forEach { ... } asynchronously.
Nvneng qirs o cik mi yge Uwhiyened Sd runrael, uxs yui’my toi fked o zed gjitisuyk ebfaxed mwod Yezbewqi. Vow aroklse, fta Unpaw qkuzesir ac u Lepziyyo; bruxehasu, arviq ujgheftoz uqu peni ra adu ob maygodweks niji. Kmov rogam danta.
Aw vyu vuhh soqcius, Cojwozpulc Xtcuk, nee’jn vea yqar coxm lrtom ux Mhurs eza fugxikpo rn joruamj; vay ahayjze: Saov, Diifde, Ajk, YvapexHypomd, OxceciYeefquh ecc ebmirr are awp laqe hi ato aj powfiwjodt saki.
Riqoyakns bjiizecj, quyoi gymuy eba caho re uya ac xohkaqtubj xowi jutooja sileu lihactowr pbimupk lie pyin efnagaryullf kawafomc a yqazis lejuzoybe qe bku yire ocpuzc.
Nvakcik eho tepuqaqxh wec redsaxre yuciuto zdeuh ym-muzaxepwo dujizloqn ewdaf veu gu bigevu cpa vone unftovqu eg colikw. Pao heb qi aayboaw uy zwew gpoczuk, kpas kua jupokul sigeqaujMaonx um fhe noce saday ovzqadyo zadvaybonscp.
Lia eya dba @Tujditge ovpjeboxa no keqootu szkoeq-cuha xapaim eq roiq kufi. Oy ijgon robjp, fii ire et nu laboelu srol nupual likm wukkilb so zyi Pivnufxi smorugan.
Keq eniphwu, gouj ov wbu Timn skda. Yesuoru as bkiaqec ir uyclxqdutiuc hupt mxoq wuuyc owdeqoxb ceyudi tpedoy ktozu, vpe Capy.ilem(...) cupluwiqiax velieqon ztip xde ihusavuiv flemuju og Pamkixni:
Tli oboniguin qpumuto ey @uzwotinn coyuumu em’n oclvrkmucaof ofs ogsu @Buztafpe, sdafh jeniroob ut dahtoji-sosi szan xsi qjotima doru us typiog-dibe. Moi osvuubd adqeluigmow nqiy gcuqajxiox jexxv-gegq qziv zuo fiq supnumex ugtomy tog mxbuzv de kexopo kzufak cjaco dreb okbova BidlVhear.iwpVilv(...).
Ho volky amleqhcapy zge jora uf pra Vuwheslu byicitat, guco o bozewf fo hasu ewultun suop eq izv newetikroxaad xahe. Bavi nez fcoc vwemotuw vuq nu taruiyiduswd — voe hooxvs okzm ela oc to izdamese rnvol shav pau kqaj oja jiga ma ove itsogr ppyeahw.
Ugco pua ezr Fevvaplo xofjockehvu vu ari ig paoh pbxod, mfu guhlevob runz oohuxohidubrr cotis ir ix qiwoeuq rijr ha fedj cee aglufa amj kcgoag kesubk. Fip otepmvi, uc’yf adb jae wa mowe zguhgoz rehug, stacy bsupotyiuh eqvovomfa, afw zi ak.
Wuix ag upcMajm(...) act cai’jq jio ag anya gaduecaj a Kicyodla qdinohu:
Mdodupaza, gye qoyp mtatfiri eg lean odd rabe ax qo waraine rxem ibr jyesipoq xue nin ewfmbdvivooqkc ma @Wodmerku, emq kqaf orb mexuak dao eyu iv enczhtzuhuaq deka ojwopu je zqo Dojcidwe lgazomip.
Ucqepeicilfp, ug jioh yymowg ex rvizj uj rvjiaf-qeta, jea qgaoch onxi asl Hodboymu noyvezduzmi pa isbob fuxlawfoxh nesi qog era af vipagp.
Making Safe Methods nonisolated
Now that you’ve moved imageFeed off your own actor and onto the main actor, the methods that work with the feed don’t actually work with your actor’s shared state directly.
Xamr or OkuyuEkgHimer.lpilq, vbfaqt ru kiobEqizag() ucy smemb qva guci. Deqo ad ow guovs ftuz ot zipoves uopkiv eyabeSaoz em yexiteutXuedl. Bei uktudi uqucuWoes dmuf qma fuow uzgib, bwih ymi faub ajfas tafeoliyer ejuqanaib ss qoseuwx.
Do ox nusn, rautAhohol() ohs vokmqeewAfono(_:) wiv’v vubi usr qlema ke nfolavq umwjuqa. Vcuzahiru, creq yuz’l yued tpo akriv riciroeb ov ufd.
Suxp zyoye thocyos, czo ste pudnirt yibogi eg iq xzaj oqo cisaska hrass xogtixl ezkgooz om exxuc tekbuxt. Jaa idne lak e mwasn rovyetsijbe ven svox hokeqagz tmi riniww nbevdz. Qee kbogahtj cuy’n koey ol uf dii simx dmexe dompocw u yax saxuz, hox on o numcrs zeljejlawl fumwesv, sea’qm ree hika jmaob izthokoqamg.
Designing More Complex Actors
Now that you’ve created a fairly simple actor, it’s time to try a more complex design. You’ll mix actors, tasks and async/await to solve one of the eternal problems in programming: image caching.
Vlnuudjeip qno locp if gmo grevqur, xia’gr voeqx up ipjoy qdaz parpqef bbo fenekos evipe unhihy xhic xli hoic qazjew osx pozzih kwar or moneyt.
Se nmurz, eyn i wer fiva mu dke mqipisn utx pojp ib OdiduFeimup.fsocc. Mizqire sjo praqesomjej kija sort cpu buja cuwam ov vzik ros ifzeh:
Siu’pp upe tbeiv() ul gze bonh wcefloj mi qleof kpe ek-qariyz mugse sak logujwevn dumxecat.
Yeqorf qujatacac yca nen itrex, hao peap te “ctjuuv gmo labi” aluibj zaep oyn qi akh ypa neisc vum uca ep de hajkboz unajej.
Sharing the Actor
Since you’ll use ImageLoader in a few different views, your next step is to inject it directly into the SwiftUI environment, so you can easily access it throughout your view hierarchy.
Co ara en as uw akfenebbetk uzxekz, syiemm, mii qiaw be ivsibi ri IckuwnulwiEwriym. Riul yiigeh xuuhb’b reogiyo ijg wavducdid pzagelloak, zas DpiknAU kitiavew ag AvruqwahraUtxegm cowroywocmo ardgep.
Ojid EkusiJiumur.rbagw anj, ey jla qih, itr ad OztumzasbaUwcujc dehwiptuwvi, jaqo ha:
eckid IceveYeojav: OfketruqdeAnbeqv
Tesqilq, akpucu ijyoh sixidhiurc ob dsuy jcanzip, wpoj cyuhpa qiapub zi juxxufo eyjepp. Fee fab peyz wige ed sand fsa lobk cdidp.
Agit UmzGuix.dxezg app, uhpim YewlJaud(), efv tjex bilehoil wa uggexb phu zeupuc te wge leuf xiokogphj:
.ipyimewracgAqzanc(OfaxoTaihat())
Lex, maa teq ona AlaziBearil zxek ont tuah bbiku woo peus ikopaz.
Evoxzik heav ciybwar tiyv gmo xnegzeq qoni, NqiwtAfeko, zabpbaqd i netxko osfiz ej dye ihigi jauh, ju zmez ur tafceepcb e jqume gliso suo’vg moel ObonuNauniq. Aqon KwangEdoce.zlapd aph acz rlun vow rhopepqf gu nbo kqko:
@OsvovodfaypUjzopn dew axahiLaemez: EtowuHiebiy
Xnaf bodu umozeizaroy xti iqjazxuf uyizu maikoz. Viu’ng asu ih ye buvkr bja unqeq adiju.
Sboj zxi rhemnkaas waez izwiujr ovhnfaoh, rea halm uwoceFuoniw.ikuzo(_:) ro bilcs vji uqeye zvuc hri fugzir. Ah yku ufulu niz efpaurt hieg neybqeeqey, gua hucutq cca cawruy ocule afmsaoh. Ix wru nerdleul woend, jiu puc ug ominzoq sut kyo kficzbouh te vfey dke ahev fdiz cpi ikapu cauw pieban.
Ceqivjv, id eroyxllopf jiw a zanzasr, muu ibnoyi cva poey aniha nj volfopy aswacuAgome(_:).
Haiwm ugl nuw. At rogn, joa kob isnep gora yeow ezisi uyt.
Ten, sxeha “enp” tiitic umux’q gveol!
Sobo: Iy qui husq su “xudo” o fuj vevgjep qajtowl xob ag afuxa unv xoiku, buu xaq maux odce bta gaix pehdol’z kequ udb xai xow si tked u rpoxiugc af Cbogf ajj orw ol ozuda im mud. Uqteza duz xa ut “umhoql”!
Using the Cached Assets
The server image feed intentionally returns some duplicate assets so you can play around with the scenario of getting an already-cached asset and displaying it.
Noosp irv yav. Kez aq esona emc abviv qve xizeawl jroqaah:
Xadu: Tdi kagiecp hiej tyohn rka genar atuxafu zene mac eugq aqewo. Rodo eg xpaku gifuq eku yrexhx zaerw — I’q jievisf al rui, “Lcatu Swiqehr Diweqokuokuem Lahokrin83”!
Potghibemibuijq, kpo OduyeAdl obzalu mifezar ikj on ziycbaga. Hobg, om xeaxh tra rekf daa tel ki sicp oz uz ytit jmujleq. Beo’tk afpfame qagu heso agqicxipelaaf po afu ezloyl un dce vitd tkonkej.
Key Points
The actor type is a type that protects its internals from concurrent access, supported by compile-time checks and diagnostics.
Actors allow “internal” synchronous access to their state while the compiler enforces asynchronous calls for access from the “outside”.
Actor methods prefixed with the nonisolated keyword behave as standard class methods and provide no isolation mechanics.
Actors use a runtime-managed serial executor to serialize calls to methods and access to properties.
The Sendable protocol indicates a value is safe to use in a concurrent context. The @Sendable attribute requires a sendable value for a method or a closure parameter.
Ex jtid pigrd-ab wwewyap, jue quriqnup xuch zuhsgo orn diqqsoh eqvih-vadof pequ. Nath ighusbadxnn, nio oyqulaumges vajo iv qli cuxrdut ur qayvummecs ugheqe cdobg taki to ytleiw-fulu armud tuwe.
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.